Compare commits

...

14 Commits

Author SHA1 Message Date
Pawla Abdul b4fa641ddd chore: add AGENTS.md with engineer task handoff instructions
Engineers were not properly picking up and completing delegated tasks.
This adds structured instructions for Paperclip task lifecycle,
git workflow, and handoff expectations.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-11 16:34:07 +00:00
groombook-cto[bot] 24a032dd9d fix(api): move Google/GitHub from plugins[] to socialProviders{} in Better-Auth config
fix(api): move Google/GitHub from plugins[] to socialProviders{} in Better-Auth config
2026-04-11 15:25:03 +00:00
Flea Flicker 13f2550ee2 fix(api): move Google/GitHub from plugins[] to socialProviders{} in Better-Auth config 2026-04-11 15:12:44 +00:00
groombook-cto[bot] f29ac2e40d Merge pull request #258 from groombook/fleaflicker/gro-546-fix-oauth-redirect-uri
CTO approved. Infra submodule update adds social auth env vars (GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET) to UAT api-patch.yaml.
2026-04-11 13:21:01 +00:00
groombook-cto[bot] bdcad0d9dc Merge pull request #257 from groombook/fleaflicker/gro-546-fix-oauth-redirect-uri
Fix GitHub/Google OAuth redirect URI configuration (GRO-546)
2026-04-11 03:01:13 +00:00
groombook-cto[bot] b1124e6a6c Merge pull request #256 from groombook/fix/gro-540-prod-oidc-env
fix(GRO-540): add missing OIDC env vars to prod API deployment
2026-04-10 22:04:52 +00:00
Paperclip 90794e4e14 fix(gro-540): add missing OIDC env vars to prod API deployment
Updates infra submodule to include OIDC_ISSUER, OIDC_CLIENT_ID,
OIDC_CLIENT_SECRET, and OIDC_INTERNAL_BASE env vars in prod api-patch.yaml.

This fixes the auth initialization failure where initAuth() found no
provider config because OIDC env vars were missing from the prod deployment
even though the groombook-auth sealed secret contained the credentials.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 21:57:48 +00:00
groombook-cto[bot] 373e35ef8e feat(GRO-537): add UAT user personas to seed script
feat(GRO-537): add UAT user personas to seed script
2026-04-10 20:23:15 +00:00
Pawla Abdul 46416586ea feat(GRO-537): add UAT Super User and Staff Groomer to seed script 2026-04-10 20:13:20 +00:00
groombook-cto[bot] 515389e067 Merge pull request #251 from groombook/fleaflicker/gro-528-seed-uat-personas
feat(db): add UAT persona staff records to seed script (GRO-528)
2026-04-10 16:16:58 +00:00
groombook-cto[bot] 191e3499fc Merge branch 'main' into fleaflicker/gro-528-seed-uat-personas 2026-04-10 16:13:03 +00:00
groombook-cto[bot] 921d708ccd Merge pull request #252 from groombook/fix/gro-534-seed-image-tag
fix: remove hardcoded seed image in promote-to-uat workflow (GRO-534)
2026-04-10 10:53:49 +00:00
Flea Flicker 8bfc6c970b feat(db): add UAT persona staff records to seed script
- Add UAT Super User and Staff User staff records creation in seedKnownUsers()
- Staff records created with oidcSub from SEED_UAT_*_OIDC_SUB env vars
- Supports linking Terraform-provisioned Authentik users to staff records

GRO-528
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 04:10:41 +00:00
Flea Flicker b8b054316c Parameterize seed script with SEED_PROFILE env var
Adds SEED_PROFILE env var accepting 'dev', 'uat', or 'demo' values:

- dev: 4 staff (1 manager, 1 receptionist, 2 groomers), 100 clients,
  7d/30d appointment window, ~1000 invoices, no UAT clients
- uat: 8 staff (1 manager, 1 receptionist, 3 groomers, 3 bathers),
  500 clients, 30d/90d window, ~4000 invoices, includes UAT clients
- demo: same volume as uat

Unset SEED_PROFILE defaults to 'uat' for backwards compatibility.
SEED_KNOWN_USERS_ONLY=true path unchanged.
All appointment dates computed relative to NOW() at seed time.
Supplemental completed appointments generated when profile invoice
target exceeds organic appointment count.

Closes groombook/groombook#247

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-10 03:38:55 +00:00
2 changed files with 59 additions and 18 deletions
+43
View File
@@ -0,0 +1,43 @@
# GroomBook — Agent Instructions
## Repo Layout
- `apps/api` — NestJS backend API
- `apps/web` — React frontend (Vite)
- `apps/e2e` — Playwright E2E tests
- `apps/groombook` — CLI / meta package
- `packages/` — shared libraries
- `charts/` — Helm charts
- `infra/` — infrastructure config
## Development
- Package manager: `pnpm` (workspace monorepo)
- Run E2E tests: `pnpm --filter @groombook/e2e test`
- Run API: `pnpm --filter @groombook/api dev`
- Run web: `pnpm --filter @groombook/web dev`
## Git Workflow
- Branch from `main` using the pattern `fix/<issue-id>-<short-desc>` or `feat/<issue-id>-<short-desc>`
- Push to origin and open a PR against `main`
- If the issue specifies an existing PR/branch, push to that branch instead of creating a new one
- Commit messages: short imperative summary, reference the issue ID
## Task Handoff (Paperclip)
When you receive an assigned task from Paperclip:
1. **Checkout the task** immediately using `POST /api/issues/{issueId}/checkout`
2. **Read the full issue description** and any comments for context
3. **Do the work** — implement the fix/feature as described
4. **Test your changes** — run relevant tests, lint, type-check
5. **Commit and push** your changes to the appropriate branch
6. **Update the task** with status `in_review` and a comment summarizing what you did, including the commit SHA and PR link
7. **Never leave a task in `in_progress` without posting a comment** explaining current state before exiting your heartbeat
If you cannot complete the work (missing info, blocked by another task, environment issue):
- Set the task to `blocked` with a comment explaining what's blocking you
- Tag your manager in the comment if escalation is needed
Do NOT silently drop tasks. Every assigned task must get a status update and comment before your heartbeat ends.
+16 -18
View File
@@ -1,7 +1,6 @@
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { genericOAuth } from "better-auth/plugins";
import { google, github } from "better-auth/social-providers";
import { getDb, authProviderConfig, eq } from "@groombook/db";
import { decryptSecret } from "@groombook/db";
@@ -173,22 +172,6 @@ export async function initAuth(): Promise<void> {
const callbackBase = `${BETTER_AUTH_URL}/api/auth/callback`;
const socialPlugins = [];
if (hasGoogle) {
socialPlugins.push(google({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
redirectURI: `${callbackBase}/google`,
}));
}
if (hasGitHub) {
socialPlugins.push(github({
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
redirectURI: `${callbackBase}/github`,
}));
}
// Build Better-Auth instance using resolved config
authInstance = betterAuth({
database: drizzleAdapter(db, {
@@ -216,8 +199,23 @@ export async function initAuth(): Promise<void> {
},
],
}),
...socialPlugins,
],
socialProviders: {
...(hasGoogle ? {
google: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
redirectURI: `${callbackBase}/google`,
},
} : {}),
...(hasGitHub ? {
github: {
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
redirectURI: `${callbackBase}/github`,
},
} : {}),
},
session: {
expiresIn: 60 * 60 * 24 * 7, // 7 days
updateAge: 60 * 60 * 24, // 1 day