diff --git a/.gitignore b/.gitignore index c74360ae0..cda6901a5 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ vite.config.js .DS_Store resources/excel/example.xlsx resources/ai-agent-plans/* +/docs/internal/ diff --git a/docs/support-copilot-ai.md b/docs/support-copilot-ai.md deleted file mode 100644 index daa7ab512..000000000 --- a/docs/support-copilot-ai.md +++ /dev/null @@ -1,179 +0,0 @@ -# CodeWeek Support Copilot — AI capabilities (Phase 1) - -**Status:** Phase 1 · AI triage + frontend code fixes as PRs into `dev` -**Phase 2:** AI-driven `artisan` changes on the server (allowlist-first, dry-run + APPROVE) -**Phase 3:** AI content/copy edits on Nova-managed records (text fields only, dry-run + APPROVE) - -This builds on the email pipeline in [support-copilot-stakeholder-guide.md](./support-copilot-stakeholder-guide.md) -and the action matrix in [support-copilot-allowed-actions.md](./support-copilot-allowed-actions.md). - ---- - -## What changed - -| Before | Now (Phase 1) | -|--------|----------------| -| Deterministic keyword triage | **AI triage** via the Cursor headless CLI, with the keyword rules as automatic fallback | -| Only user data actions (`user_restore`, `user_profile_update`) | Adds **`code_change`**: a frontend/code fix implemented by a Cursor cloud agent as a **PR into `dev`** | -| — | Optional **dev → live release PR** opened for a human to merge (never auto-merged) | - -The safety model is unchanged: in dry-run mode every write (including `code_change`) -sends a summary and only runs after an emailed **APPROVE** from an allowed domain. - ---- - -## One key, two Cursor surfaces - -A single `CURSOR_API_KEY` (a Cursor **service account** key is recommended) powers both: - -| Surface | Used for | How | -|---------|----------|-----| -| Cursor **headless CLI** (`agent -p --output-format json`) | The triage "brain" | Runs on the Forge server | -| Cursor **Cloud Agents API** (`POST https://api.cursor.com/v1/agents`) | Code change + PR into `dev` | Runs in Cursor's cloud against the connected GitHub repo | - -Prerequisites: - -- Install the CLI on the server: `curl https://cursor.com/install -fsS | bash` -- Connect `github.com/codeeu/codeweek` to Cursor (Cloud Agents need GitHub access) -- Set the env vars below in Forge - ---- - -## Flow - -```mermaid -flowchart TD - A[Ticket email] --> B[AI triage - Cursor CLI] - B --> C{case_type} - C -->|user data| D[user_restore / profile_update] - C -->|code_change| E[Dry-run: exact agent prompt + target branch] - E --> F[Summary email -> APPROVE] - F -->|APPROVE| G[Cloud agent: branch + PR into dev] - G --> H[poll-agents: capture PR link] - H --> I[Report email: PR link] - H -->|pr_only| J[Open/reuse dev -> live release PR] -``` - -1. **Triage** — the CLI returns a JSON classification. If AI is disabled or fails, the keyword rules run instead. -2. **Dry-run** — for `code_change` the summary email shows the **exact instruction** the agent will receive and the target branch (`dev`). Nothing runs yet. -3. **APPROVE** — reply `APPROVE` in-thread (same rules as all other actions). -4. **Execute** — a Cursor cloud agent makes the change on a `cursor/...` branch and opens a **PR into `dev`**. -5. **Report** — `support:ai:poll-agents` (scheduled every minute) captures the PR link and emails it, and — when `SUPPORT_AI_LIVE_PROMOTION=pr_only` — opens/reuses a **dev → live** release PR for a developer to merge. - -**Nothing is ever merged or deployed automatically.** - ---- - -## Configuration (`config/support_ai.php`) - -| Env var | Default | Purpose | -|---------|---------|---------| -| `SUPPORT_AI_ENABLED` | `false` | Master switch for all AI features | -| `CURSOR_API_KEY` | — | Cursor service-account key (CLI + Cloud API) | -| `SUPPORT_AI_TRIAGE_ENABLED` | `true` | Use AI triage (falls back to keywords) | -| `SUPPORT_AI_CLI_BIN` | `agent` | Path to the Cursor CLI binary | -| `SUPPORT_AI_CLI_MODEL` | `gpt-5.4-mini-medium` | Model for triage (any id from `agent models`) | -| `SUPPORT_AI_CODE_CHANGE_ENABLED` | `false` | Enable the `code_change` action | -| `SUPPORT_AI_REPO_URL` | `https://github.com/codeeu/codeweek` | Repo for cloud agents | -| `SUPPORT_AI_DEV_BRANCH` | `dev` | PR target branch | -| `SUPPORT_AI_CLOUD_MODEL` | `composer-2.5` | Model for the cloud coding agent (verify via `GET /v1/models`) | -| `SUPPORT_AI_AUTO_CREATE_PR` | `true` | Agent opens the PR on completion | -| `SUPPORT_AI_MAX_POLL_MINUTES` | `30` | Give up polling an agent after N minutes | -| `SUPPORT_AI_LIVE_PROMOTION` | `pr_only` | `pr_only` opens dev→live PR; `none` disables | -| `SUPPORT_AI_LIVE_BRANCH` | `master` | Live branch (Forge auto-deploys this) | -| `SUPPORT_GITHUB_REPO` | `codeeu/codeweek` | owner/repo for the promotion PR | -| `SUPPORT_GITHUB_TOKEN` | — | Token to open the dev→live PR (skipped if absent) | - ---- - -## Commands - -| Command | Purpose | -|---------|---------| -| `php artisan support:ai:setup-check` | Verify the Cursor key, CLI binary path, model availability, DB columns, and GitHub token | -| `php artisan support:ai:poll-agents` | Check in-flight code-change agents, capture PR links, report, open dev→live PR (scheduled every minute when enabled) | -| `php artisan support:ai:promote-dev-to-live` | Manually open/reuse the dev → live release PR | - ---- - -## Rollout checklist - -0. Run `php artisan support:ai:setup-check` and fix any warnings before enabling. -1. `SUPPORT_AI_ENABLED=true`, set `CURSOR_API_KEY`, keep `SUPPORT_AI_CODE_CHANGE_ENABLED=false` → validate AI triage only. -2. Install Cursor CLI on the server; confirm `CURSOR_API_KEY=... agent -p --force "hello"` works (the `--force` flag skips the Workspace Trust prompt — the bot passes it automatically). -3. Connect the GitHub repo to Cursor, then `SUPPORT_AI_CODE_CHANGE_ENABLED=true` → first `code_change` ticket, verify the dry-run email shows the exact prompt. -4. APPROVE once; confirm a PR opens into `dev` and the report email arrives with the link. -5. Set `SUPPORT_GITHUB_TOKEN` to enable the dev→live release PR. - -Keep `SUPPORT_GMAIL_DRY_RUN=true` throughout so every change still needs an emailed APPROVE. - ---- - -## Phase 2 — AI `artisan` changes over SSH - -When triage classifies a ticket as `artisan_command`, the bot prepares a server -maintenance command and runs it through the same dry-run → APPROVE → execute → -report pipeline as every other write action. **Disabled by default** -(`SUPPORT_AI_ARTISAN_ENABLED=false`). - -- **Allowlist-first** (`App\Services\Support\Artisan\ArtisanActionRegistry`): the AI may - only pick a permitted command, and every argument/option is validated by type - (email, token, name). Current allowlist: `support:user-audit`, `support:event-audit`, - `support:user-restore`, `support:user-update-profile`. -- **Guarded raw fallback** (`SUPPORT_AI_ARTISAN_ALLOW_RAW=true`): if no allowlisted command - fits, the AI may propose a bare `artisan` command. It is rejected if it contains shell - metacharacters or hits the deny-list (`migrate:fresh`, `db:wipe`, `tinker`, `down`, …), - treated as a write, and **never auto-simulated** — the exact command is emailed for APPROVE. -- **Execution safety:** commands run via the `Process` array form (`php artisan …`), so - argument values can never be interpreted by a shell. Write commands that support - `--dry-run` are previewed with it during diagnostics; read-only commands are run as-is. - Re-validated against the allowlist/deny-list again at execution time (not trusting the - stored approval payload). Output is captured and truncated to `SUPPORT_AI_ARTISAN_OUTPUT_LIMIT`. -- **Report:** the completion email shows the exact command and its output. - -### Phase 2 env - -```dotenv -SUPPORT_AI_ARTISAN_ENABLED=false # master switch for artisan actions -SUPPORT_AI_ARTISAN_ALLOW_RAW=true # allow AI-proposed (non-allowlisted) commands -SUPPORT_AI_ARTISAN_TIMEOUT=120 # per-command timeout (seconds) -SUPPORT_AI_ARTISAN_OUTPUT_LIMIT=8000 # captured output cap (characters) -``` - -`artisan_command` must also be present in `support_gmail.allowed_write_actions` -(it is by default) and `support:ai:setup-check` verifies this. - ---- - -## Phase 3 — AI content edits on Nova-managed records - -When triage classifies a ticket as `content_update`, the bot proposes an editorial -text change to an allowlisted content record and runs it through the same dry-run → -APPROVE → execute → report pipeline. The records are Nova resources, so a reviewer -can also adjust them by hand. **Disabled by default** (`SUPPORT_AI_CONTENT_ENABLED=false`). - -- **Model allowlist** (`App\Services\Support\Content\ContentActionRegistry`): the AI may - only edit listed content models (pages, homepage slides, FAQ items, menus, events, - podcasts, partners, …). Page-style singletons are looked up automatically; other - records are referenced by id or a unique field. -- **Text fields only** (`ContentFieldResolver`): editable columns are resolved at runtime - to string/text columns **minus** a structural deny-list (URLs, slugs, flags, relations, - identifiers, SEO/keyword/category fields) and minus any non-string cast (boolean / array - / date / int). No hand-maintained per-model column list. -- **Value guards** (`ContentUpdateService::validateValue`): each new value must be plain - text — URLs, `www.` references, and HTML/markup are rejected, length is capped at - `SUPPORT_AI_CONTENT_MAX_FIELD_LENGTH`. Fields whose current value is a Laravel - translation key (e.g. `hackathons.hero.title`) are left untouched. -- **Exact diff + re-validation:** diagnostics computes a before→after diff (shown in the - approval email); execution re-runs the full plan/validation before saving — it never - trusts the stored payload. The completion email shows the applied before→after. - -### Phase 3 env - -```dotenv -SUPPORT_AI_CONTENT_ENABLED=false # master switch for content edits -SUPPORT_AI_CONTENT_MAX_FIELD_LENGTH=5000 -``` - -`content_update` must also be present in `support_gmail.allowed_write_actions` -(it is by default) and `support:ai:setup-check` verifies this. diff --git a/docs/support-copilot-allowed-actions.md b/docs/support-copilot-allowed-actions.md deleted file mode 100644 index 9e65ea5dc..000000000 --- a/docs/support-copilot-allowed-actions.md +++ /dev/null @@ -1,155 +0,0 @@ -# CodeWeek Support Copilot — Allowed actions reference - -**Version:** V1 · **Last updated:** May 2026 - -This document lists everything the support copilot **allows**, **automates**, and **blocks**. - ---- - -## 1. Who can send tickets (ingest) - -| Rule | Allowed | -|------|---------| -| Sender email domain | `@matrixinternet.ie`, `@codeweek.eu` (config: `SUPPORT_GMAIL_ALLOWED_DOMAINS`) | -| Extra explicit senders | Optional list via `SUPPORT_GMAIL_ALLOWED_SENDERS` | -| Subject line (new tickets) | Must contain `codeweek-support` (config: `SUPPORT_GMAIL_SUBJECT_PREFIX`) | -| Subject line (APPROVE replies) | Must be in the **`[CW-SUPPORT #…]`** thread (poll also searches this prefix) | -| Teacher / parent Gmail, schools, etc. | **Not ingested** — staff must send a new email from an allowed domain | - ---- - -## 2. Who can approve writes (email reply) - -| Rule | Allowed | -|------|---------| -| Reply keywords (first line only) | `APPROVE`, `YES`, `PROCEED` (case-insensitive) | -| Sender domain | Same as ingest: `@matrixinternet.ie`, `@codeweek.eu` | -| Thread | Reply in the same Gmail thread as the `[CW-SUPPORT #…]` summary when possible | - ---- - -## 3. Automated write actions (require APPROVE when `SUPPORT_GMAIL_DRY_RUN=true`) - -These are the **only** actions that can change production data via the email pipeline after **APPROVE**: - -| Action ID | Case type | What it does | Required in ticket | -|-----------|-----------|--------------|-------------------| -| `user_restore` | `account_restore` | Restores a **soft-deleted** user | User email + words like *restore*, *deleted account* | -| `user_profile_update` | `profile_update` | Updates `firstname` and/or `lastname` on `users` | User email + requested first/last name | -| `code_change` | `code_change` | AI cloud agent implements a frontend/code fix and opens a **PR into `dev`** (never deploys) | Description of the bug/change in the website code | -| `artisan_command` | `artisan_command` | Runs an allowlisted (or guarded AI-proposed) `artisan` maintenance command on the server after dry-run + APPROVE | Request needing a server maintenance command; gated by `SUPPORT_AI_ARTISAN_ENABLED` | -| `content_update` | `content_update` | Edits **text fields only** on allowlisted Nova-managed content records (pages, slides, FAQs, …) after dry-run + APPROVE; never touches URLs/flags/relations | Request to fix/reword copy on an existing page or record; gated by `SUPPORT_AI_CONTENT_ENABLED` | - -Configured in `config/support_gmail.php` → `allowed_write_actions`. AI features are -configured in `config/support_ai.php` — see [support-copilot-ai.md](./support-copilot-ai.md). - ---- - -## 4. Case types (triage classification) - -| Case type | Trigger keywords (examples) | Automated write? | -|-----------|----------------------------|----------------| -| `account_restore` | soft-deleted, deleted, restore account | Yes → `user_restore` + APPROVE | -| `profile_update` | update profile, first name, last name, change name | Yes → `user_profile_update` + APPROVE | -| `certificate_issue` | certificate, cert | **No** — summary / manual reply | -| `missing_events` | missing event, events missing | **No** | -| `duplicate_account` | duplicate, two accounts | **No** | -| `role_issue` | role, permission | **No** | -| `unknown` | (none matched) | **No** | - ---- - -## 5. Read-only / manual tools (no email APPROVE) - -| Tool | CLI | Internal API | Email APPROVE | -|------|-----|--------------|---------------| -| User audit | — | `POST /tools/user-audit` | No | -| Event audit | `support:event-audit` (if registered) | `POST /tools/event-audit` | No | -| Email change | `support:user-update-email {from} {to}` | — | **No** (CLI / dev only) | -| Profile name change | `support:user-update-profile {email} --firstname= --lastname=` | `POST /tools/user-profile-update` | Yes (via pipeline + APPROVE) | -| Gmail test | `support:gmail:test` | — | N/A | -| Gmail poll | `support:gmail:poll` | — | N/A | - ---- - -## 6. Profile update — allowed fields - -| Field | Column | Allowed via copilot? | -|-------|--------|----------------------| -| First name | `users.firstname` | **Yes** | -| Last name | `users.lastname` | **Yes** | -| Email | `users.email` | **No** (use `support:user-update-email`) | -| Display email | `users.email_display` | **No** | -| Twitter, website, bio, tag, country | various | **No** (user edits in UI or manual) | -| Delete / restore account | soft delete | Restore only via `user_restore` | - -**Rejected as names:** placeholder text such as `Last Name`, `First Name`, `Your details`, empty strings. - ---- - -## 7. Safety flags (environment) - -| Variable | Typical prod | Effect | -|----------|--------------|--------| -| `SUPPORT_GMAIL_ENABLED` | `true` | Turns on polling | -| `SUPPORT_GMAIL_POLL_INTERVAL_MINUTES` | `1` | Scheduler frequency (1–5 typical; increase if Gmail rate limits) | -| `SUPPORT_GMAIL_DRY_RUN` | `true` | Pipeline sends summaries; writes need **APPROVE** | -| `SUPPORT_GMAIL_NOTIFY_EMAIL` | `codeweek@matrixinternet.ie` | Dry-run summary recipient | -| `SUPPORT_GMAIL_ALLOWED_DOMAINS` | `matrixinternet.ie,codeweek.eu` | Ingest + approve senders | - ---- - -## 8. Gmail API scopes - -| Scope | Purpose | -|-------|---------| -| `gmail.readonly` | Poll inbox, read approval replies | -| `gmail.send` | Send dry-run summaries and completion emails | - ---- - -## 10. Email notifications (what you receive) - -| When | Email subject (example) | -|------|-------------------------| -| Ticket processed (dry-run) | `[CW-SUPPORT #10] Support copilot - dry run review` | -| After you reply **APPROVE** and action runs | `[CW-SUPPORT #10] Support copilot - action completed` or `action failed` | - -Completion emails go to the same recipient as the dry-run summary (`SUPPORT_GMAIL_NOTIFY_EMAIL` unless overridden). Disable with `SUPPORT_GMAIL_SEND_COMPLETION_EMAIL=false`. - ---- - -## 9. Not allowed / out of scope (V1) - -- Ingest mail without `codeweek-support` in subject -- Approve from non-allowlisted domains -- Auto-change email via support email (CLI only) -- Auto-issue or regenerate Excellence certificates from email -- Auto-merge duplicate accounts -- Auto-change roles/permissions -- LLM-only decisions without DB checks (not implemented) - ---- - -## 10. Quick test commands (technical) - -```bash -# Profile update dry-run -php artisan support:user-update-profile bernard@matrixinternet.ie --firstname=Bernard --lastname=Hanna --dry-run - -# Profile update live (bypasses email; use on server with care) -php artisan support:user-update-profile bernard@matrixinternet.ie --firstname=Bernard --lastname=Hanna - -# Simulated pipeline + summary email -php artisan support:gmail:test - -# Check config -php artisan support:gmail:setup-check -``` - ---- - -See also: - -- [support-copilot-stakeholder-guide.md](./support-copilot-stakeholder-guide.md) -- [support-copilot-ai.md](./support-copilot-ai.md) — AI triage + frontend code PRs (Phase 1) diff --git a/docs/support-copilot-stakeholder-guide.md b/docs/support-copilot-stakeholder-guide.md deleted file mode 100644 index 0c79e4e3f..000000000 --- a/docs/support-copilot-stakeholder-guide.md +++ /dev/null @@ -1,451 +0,0 @@ -# CodeWeek Support Copilot — Stakeholder guide - -**Version:** V1 (dry-run) · **Last updated:** May 2026 - ---- - -## What this is - -CodeWeek has an automated **support assistant** that: - -- Watches a dedicated support inbox -- Picks up qualifying emails automatically (about every minute by default) -- Runs basic checks on the user account mentioned in the email -- Sends a **summary email** to **codeweek@matrixinternet.ie** so the team can review before any change is made - -**Nothing is changed automatically** unless the summary explicitly asks for approval and someone approves by email. - ---- - -## Who should use this - -Anyone at **Matrix Internet** or **CodeWeek** (`@matrixinternet.ie` or `@codeweek.eu`) who needs help with a CodeWeek user account (login issues, deleted account, etc.). - ---- - -## How to log a support request (3 steps) - -### Step 1 — Send an email to the support inbox - -**To:** `________________________` - -*(Fill in: the Gmail inbox connected to the copilot — ask your technical contact if unsure.)* - -### Step 2 — Use the correct subject line - -The subject **must include**: - -```text -codeweek-support -``` - -**Good examples:** - -- `codeweek-support — user cannot log in` -- `codeweek-support — restore account for parent@example.com` - -**Bad examples (will not be processed):** - -- `User cannot log in` *(missing codeweek-support)* -- `Fwd: RE: login issue` *(forward only — send a new email with the prefix)* - -### Step 3 — Write a clear message - -Include: - -1. **The user’s email address** on CodeWeek (required) -2. **What the problem is** in plain language -3. **What you want done** (e.g. “check if account is deleted and restore if possible”) - -**Example email:** - -```text -To: [support inbox] -From: colleague@matrixinternet.ie -Subject: codeweek-support — account restore request - -Hello, - -Please investigate user: serin34@yahoo.com - -They cannot log in. The account may have been soft-deleted. -Please check and restore if appropriate. - -Thanks, -[Name] -``` - -**Rules:** - -| Requirement | Detail | -|-------------|--------| -| **Send from** | `@matrixinternet.ie` or `@codeweek.eu` only | -| **Subject** | Must contain `codeweek-support` | -| **Body** | Must include the affected user’s email address | - -Emails from other domains (Gmail, Yahoo, schools, etc.) are **not processed**, even if forwarded. - ---- - -## Typical support tickets (examples) - -These are real-world requests the copilot is designed for. **Staff must not forward the teacher’s email as-is** — copy the facts into a new email from `@matrixinternet.ie` or `@codeweek.eu` with `codeweek-support` in the subject. - ---- - -### Example 1 — Teacher accidentally deleted account (restore) - -**Situation (incoming request to the team)** - -A colleague or EU CodeWeek coordinator receives a message like this: - -```text -Hi Bernard, - -The teacher below has accidentally deleted her account and asks to be recovered. - -Registration email: laurafuso1@gmail.com -CodeWeek 4all code: cw25-x6LtQ - -Thank you, -Regards, -Rachele -``` - -The public-facing team may already have replied (e.g. asking for email and activity codes). Once you have those details, **log the ticket for the copilot** as below. - -**What to send to the support copilot** - -```text -To: [support inbox] -From: rachele@matrixinternet.ie -Subject: codeweek-support — restore deleted teacher account - -Hello, - -Request type: restore deleted account - -User registration email: laurafuso1@gmail.com -CodeWeek 4all code: cw25-x6LtQ - -The teacher accidentally deleted her account and needs it recovered. -Please check if the account is soft-deleted and restore if appropriate. - -Reported by: Rachele (EU CodeWeek coordination) -``` - -**Why this wording matters** - -| Detail in the ticket | Purpose | -|----------------------|---------| -| `codeweek-support` in subject | Required so the inbox is polled | -| `restore` / `deleted account` | Helps triage classify as **account restore** | -| `laurafuso1@gmail.com` | Target user for diagnostics | -| `cw25-x6LtQ` | Extra context for manual verification (V1 may not auto-use the code yet) | -| Work email sender | Required for ingest and for any later **APPROVE** reply | - -**What the team receives (~1 minute later)** - -An email to **codeweek@matrixinternet.ie** similar to: - -```text -[CW-SUPPORT #…] Support copilot - dry run review - -Case #… -Subject: codeweek-support — restore deleted teacher account -Type: account_restore -Risk: low -Target: laurafuso1@gmail.com - -Diagnostics findings: … - -Proposed action: user_restore -To execute this change, reply to this email with a single line: -APPROVE -``` - -If diagnostics show the user is soft-deleted and restore is safe, a reviewer replies **APPROVE** (from `@matrixinternet.ie` or `@codeweek.eu`) in the **same thread**. - -**After restore** - -Tell the teacher they can sign in again and download certificates from: - -https://codeweek.eu/certificates - -*(Same guidance as in the standard EU CodeWeek reply template.)* - -**If the summary says “No automated write action proposed”** - -- Check Nova → Support Cases for the case number -- Escalate to the technical team with the case # and the 4all code - ---- - -### Example 2 — “Did not receive Certificate of Excellence” (investigation, often not a bug) - -**Situation (incoming request to the team)** - -EU CodeWeek receives a contact form message; a coordinator forwards it internally: - -```text -Hi Bernard, - -Can you please see the below? They didn't receive the certificate. - -Code: cw25-iKlWI - ---- - -From: Code Week -Subject: New Contact Form Submission - -First Name: Concetta -Last Name: Garufo -Email: concetta.garufo@gmail.com -Subject: Certificates - -Message: -Good morning, I am writing to request information regarding the 2025 Certificate -of Excellence, which we have not yet received. Our school participated in the -activities using the code cw25-iKlWI. The name of the school is I.C. "S. Gangitano", -Canicatti (Ag). I look forward to hearing from you soon. Kind regards -``` - -**What to send to the support copilot** - -```text -To: [support inbox] -From: bernard@matrixinternet.ie -Subject: codeweek-support — Certificate of Excellence not received - -Hello, - -Request type: certificate inquiry - -Contact email: concetta.garufo@gmail.com -CodeWeek 4all code: cw25-iKlWI -School: I.C. "S. Gangitano", Canicatti (Ag) - -The school reports they did not receive the 2025 Certificate of Excellence. -Please check eligibility for this code and summarise why a certificate was or -was not issued. - -Reported via: EU CodeWeek contact form (forwarded by Rachele) -``` - -**What the copilot does today (V1)** - -| Step | Automatic? | Result | -|------|------------|--------| -| Ingest email | Yes | Case created if rules met | -| Triage | Yes | Type **`certificate_issue`** (keyword “certificate”) | -| User lookup | Yes | Audit for `concetta.garufo@gmail.com` | -| **4all code eligibility report** | **Not yet** | Code `cw25-iKlWI` is **not** auto-analysed in V1 | -| Proposed write / APPROVE | No | **No account change** — this is an explanation ticket | - -You still get a dry-run summary at **codeweek@matrixinternet.ie**, but a **human (or dev team)** must confirm eligibility using internal tools until the copilot is extended. - -**Actual outcome for this ticket (correct behaviour — not a platform bug)** - -Investigation showed code **cw25-iKlWI** was **not** selected as a **2025 Certificate of Excellence** winner, so **no Excellence certificate was generated or sent**. - -For **2025**, a code qualifies if it reaches **either**: - -- **At least 10 organisers** across approved activities, **or** -- **At least 3 countries** across approved activities - -**This code’s stats:** - -| Metric | Value | Excellence threshold (2025) | Met? | -|--------|-------|-----------------------------|------| -| Activities | 10 | — | — | -| Participants | 428 | — | — | -| Organisers | 8 | ≥ 10 | No | -| Countries | 1 | ≥ 3 | No | - -**Suggested reply to the school / coordinator** - -```text -We checked CodeWeek 4all code cw25-iKlWI for 2025. It was not selected as a -Certificate of Excellence winner, so no Excellence certificate was generated -or sent for this code. - -For 2025, a code qualifies if it reaches either at least 10 organisers or -at least 3 countries across approved activities. This code recorded -10 activities, 428 participants, 8 organisers, and 1 country, so it did not -meet the 2025 Excellence thresholds. - -Participation certificates (where applicable) can still be available from the -user’s account at https://codeweek.eu/certificates after signing in. -``` - -**Will emailing the inbox “fix” this?** - -**No automated fix** — there is nothing broken to repair. The goal is a **clear summary of why** no Excellence certificate was issued so the team can reply accurately. - -**V1:** Email → case + user audit → manual eligibility check → reply using template above. - -**Planned improvement:** Copilot reads the **4all code**, compares activity stats to Excellence rules, and includes a **ready-made explanation** in the dry-run email (no APPROVE needed). - -**If the summary says “No automated write action proposed”** - -That is **expected** for this ticket type. Use Nova case # + internal checks, then send the explanation to the teacher. - ---- - -### Example 3 — Fix profile first / last name (with APPROVE) - -**Situation:** A user’s profile shows the full name in the first-name field (e.g. First name `Bernard Hanna`, Last name `Last Name`). - -**What to send to the support copilot:** - -```text -To: [support inbox] -From: bernard@matrixinternet.ie -Subject: codeweek-support — update user profile name - -Email: bernard@matrixinternet.ie - -Current first name: Bernard Hanna -Current last name: Last Name - -Requested first name: Bernard -Requested last name: Hanna - -Please update the profile name fields. Email address must stay the same. -``` - -**Expected:** Dry-run summary with **Before** / **After** names and **Proposed action: user_profile_update**. Reply **APPROVE** to apply. - -**Full list of allowed actions:** see [support-copilot-allowed-actions.md](./support-copilot-allowed-actions.md). - ---- - -## What happens after you send the email - -| When | What happens | -|------|----------------| -| **Within ~1 minute** | The system reads the inbox and creates a support case | -| **Shortly after** | A summary is emailed to **codeweek@matrixinternet.ie** | -| **Subject of summary** | `[CW-SUPPORT #123] Support copilot - dry run review` | -| **Sender** | Code Week Bot (automated) | - -The summary includes: - -- Case number -- Your original subject -- User email checked -- What the system found -- Whether it **proposes an action** or only reports findings - -**You do not need to use admin tools or run commands** — logging the ticket is done by email only. - ---- - -## How to approve a change (only when asked) - -Read the summary email carefully. - -### If it says: *“No automated write action proposed”* - -- **Do not** reply `APPROVE` -- Handle the case manually (or ask the dev team / check Nova if you have access) - -### If it says: *“To execute this change, reply… APPROVE”* - -1. **Reply in the same email thread** (use Reply, not a new email) -2. Put **only this on the first line** of your reply: - - ```text - APPROVE - ``` - - (`APPROVED`, `YES`, or `PROCEED` also work. Must be on its own line near the top of the reply.) -3. Send from **`@matrixinternet.ie`** or **`@codeweek.eu`** -4. Wait up to ~1 minute for the system to process your reply -5. You will receive a **follow-up email** in the same thread: - - **`action completed`** — change was applied - - **`action failed`** — change was not applied (see errors in the email; check Nova) - ---- - -## What the system can and cannot do (V1) - -| Request | Supported via email? | Notes | -|---------|----------------------|--------| -| Check user / account status | Yes | You get a summary | -| **Restore soft-deleted account** | Yes, with approval | Use words like *restore*, *soft-deleted*, *deleted account*; reply **APPROVE** if proposed | -| **Update profile first / last name** | Yes, with approval | Use *update profile*, *first name*, *last name*; reply **APPROVE** if proposed | -| Change user email address | **No** | Contact dev team — use CLI `support:user-update-email` | -| **Certificate of Excellence not received** | Partial (V1) | Classifies ticket + user audit; **4all code eligibility explanation is manual** (see Example 2) | -| Missing events / roles | Partial | Summary only; manual follow-up | -| Vague or unclear requests | Limited | May show “unknown” type — team reviews manually | - ---- - -## Frequently asked questions - -**Q: I didn’t get a summary at codeweek@matrixinternet.ie** - -Check: correct inbox, subject contains `codeweek-support`, sent from `@matrixinternet.ie` or `@codeweek.eu`, user email in body. Wait 10 minutes, then contact your technical lead. - -**Q: Can I forward an email from a teacher/parent?** - -Not as-is. Send a **new** email from your work address with `codeweek-support` in the subject and the user’s email in the body. - -**Q: Is it safe? Will it change production data without us knowing?** - -V1 is **dry-run by default**. Most tickets only send a summary. Writes (e.g. account restore) only run after an explicit **APPROVE** from an allowed address, and only when the summary proposes that action. - -**Q: Who gets the summary?** - -**codeweek@matrixinternet.ie** (team inbox). The person who logged the ticket does not automatically get a copy unless they’re on that distribution. - -**Q: Where can admins see full detail?** - -Nova → **Support Cases** (internal admin). - ---- - -## Escalation - -| Situation | Contact | -|-----------|---------| -| Email not picked up after 10+ minutes | Technical lead / dev team | -| Wrong user, urgent production issue | Dev team + Nova case # from summary | -| Email change, merge accounts, complex data fix | Dev team (not automated in V1) | - -**Technical contact:** `________________________` - -**Support inbox address:** `________________________` - ---- - -## Quick reference card - -```text -TO: [support inbox] -FROM: @matrixinternet.ie or @codeweek.eu -SUBJECT: codeweek-support — [short description] -BODY: User email: someone@example.com - Problem: ... - Request: ... - -WAIT: ~1 min → summary at codeweek@matrixinternet.ie - -APPROVE: Only if summary asks — reply with first line: APPROVE -``` - ---- - -## Internal reference (technical team) - -| Setting | Value | -|---------|--------| -| Subject prefix | `codeweek-support` | -| Summary recipient | `codeweek@matrixinternet.ie` | -| Allowed sender domains | `matrixinternet.ie`, `codeweek.eu` | -| Config | `config/support_gmail.php` | -| Verify on server | `php artisan support:gmail:setup-check` | -| **Allowed actions (full list)** | [support-copilot-allowed-actions.md](./support-copilot-allowed-actions.md) | -| CLI profile fix | `php artisan support:user-update-profile {email} --firstname= --lastname= [--dry-run]` |