Initial project scaffolding
This commit is contained in:
69
docs/archive/handoffs/handoff-2026-03-25-project-scaffold.md
Normal file
69
docs/archive/handoffs/handoff-2026-03-25-project-scaffold.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Session Handoff: oysqn.app Initial Scaffold
|
||||
**Date:** 2026-03-25
|
||||
**Session Duration:** ~30 min
|
||||
**Session Focus:** Create new project oysqn.app — Nuxt + Ionic Vue + PrimeVue + Supabase
|
||||
**Context Usage at Handoff:** Low
|
||||
|
||||
## What Was Accomplished
|
||||
|
||||
1. Created `/home/ptoal/Dev/mobile-projects/oysqn.app/` project scaffold
|
||||
2. Configured Nuxt 4 + @ionic/vue + PrimeVue 4 + @nuxtjs/supabase + @pinia/nuxt + @vite-pwa/nuxt
|
||||
3. Created app shell: `app/app.vue` with IonApp + IonMenu + IonRouterOutlet
|
||||
4. Created ionic plugin: `app/plugins/ionic.client.ts`
|
||||
5. Created skeleton pages: `app/pages/index.vue`, `app/pages/login.vue`, `app/pages/auth/callback.vue`
|
||||
6. Created skeleton stores: `app/stores/auth.ts`, `app/stores/boat.ts`
|
||||
7. Created auth middleware: `app/middleware/auth.ts`
|
||||
8. Created shared composable: `app/composables/useToast.ts`
|
||||
9. Created placeholder Supabase types: `types/supabase.ts`
|
||||
10. Copied docs: `docs/planning/`, `docs/context/`, `templates/`
|
||||
11. Created project-specific `CLAUDE.md`
|
||||
|
||||
## Exact State of Work in Progress
|
||||
|
||||
- Dependencies NOT yet installed — run `yarn install` to install
|
||||
- Supabase project NOT yet configured — `.env` file needed with SUPABASE_URL + SUPABASE_KEY
|
||||
- Supabase schema NOT yet created — `types/supabase.ts` is a placeholder with inferred types from bab-app domain
|
||||
- No icons in `public/icons/` — copy from bab-app or generate new ones
|
||||
|
||||
## Decisions Made This Session
|
||||
|
||||
- USE IonRouterOutlet instead of NuxtPage BECAUSE user decision — enables Ionic page transitions and lifecycle hooks
|
||||
- USE Supabase INSTEAD OF Appwrite BECAUSE user decision — new project rewrite
|
||||
- USE mode: 'md' in IonicVue plugin BECAUSE consistent cross-platform appearance in PWA
|
||||
- USE @nuxtjs/supabase module BECAUSE handles SSR-safe client creation and useSupabaseUser() composable
|
||||
- USE magic link + OTP auth only (no password) BECAUSE carried forward from bab-app — confirmed auth model
|
||||
- NO @ionic/vue-router BECAUSE Nuxt manages the router; IonRouterOutlet from @ionic/vue works with standard Vue Router
|
||||
|
||||
## Key Numbers
|
||||
|
||||
- 0 TypeScript errors at scaffold time (no yarn install yet)
|
||||
- 3 skeleton pages created
|
||||
- 2 skeleton stores created
|
||||
- 3 tables in placeholder types/supabase.ts: boats, members, reservations
|
||||
|
||||
## What the NEXT Session Should Do
|
||||
|
||||
1. **First**: Run `yarn install` in `/home/ptoal/Dev/mobile-projects/oysqn.app/`
|
||||
2. **Then**: Create Supabase project at supabase.com, copy URL + anon key to `.env`
|
||||
3. **Then**: Run `npx supabase gen types typescript --project-id YOUR_ID > types/supabase.ts` to get real types
|
||||
4. **Then**: Design Supabase schema (tables: boats, members, reservations, interval_templates, intervals, certifications, reference_docs)
|
||||
5. **Then**: Implement auth pages (login.vue — magic link/OTP)
|
||||
6. **Then**: Run `yarn dev` and verify IonRouterOutlet renders correctly
|
||||
|
||||
## Open Questions Requiring User Input
|
||||
|
||||
- [ ] Supabase project ID — needed to generate real types and configure .env
|
||||
- [ ] Should the scheduling refactor (new resource picker + booking flow) be designed before or after implementing auth + boat pages?
|
||||
- [ ] Copy icons from bab-app or generate new ones for oysqn.app?
|
||||
- [ ] Should the admin section use a separate IonMenu or just role-based visibility in the same menu?
|
||||
|
||||
## Assumptions That Need Validation
|
||||
|
||||
- ASSUMED: magic link + OTP auth carried forward from bab-app — validate with Patrick
|
||||
|
||||
## Files to Load Next Session
|
||||
|
||||
- `app/app.vue` — if modifying the app shell
|
||||
- `app/plugins/ionic.client.ts` — if debugging Ionic setup
|
||||
- `types/supabase.ts` — after regenerating from real Supabase project
|
||||
- `CLAUDE.md` — for project context
|
||||
16
docs/context/archive-rules.md
Normal file
16
docs/context/archive-rules.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Archive Rules
|
||||
|
||||
## Raw File Archival
|
||||
|
||||
After creating a Source Document Summary for any raw file:
|
||||
1. Move the raw file to `docs/archive/`
|
||||
2. Record the move in the source summary's header: `Archived From: [original path]`
|
||||
3. Do not read from `docs/archive/` unless the user explicitly says "go back to the original [filename]"
|
||||
|
||||
## Summary Lifecycle Rules
|
||||
|
||||
1. **Session handoffs expire**: After a new handoff is written, the previous handoff moves to `docs/archive/handoffs/`. Only the latest handoff stays in `docs/summaries/`.
|
||||
2. **Decision records persist**: Decision records (DR-*) stay in `docs/summaries/` permanently — they are institutional memory.
|
||||
3. **Source summaries persist**: Source document summaries stay until the project ends — they replace raw documents.
|
||||
4. **Analysis summaries**: Keep only the latest version. If re-run, the new one replaces the old (archive the old one).
|
||||
5. **Maximum active summaries**: If `docs/summaries/` exceeds 15 files, consolidate older source summaries into a single `project-digest.md` and archive the originals.
|
||||
23
docs/context/processing-protocol.md
Normal file
23
docs/context/processing-protocol.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Document Processing Protocol
|
||||
|
||||
Use this whenever you need to process multiple documents or large files.
|
||||
|
||||
## For 1-3 Short Documents (< 2K words each)
|
||||
|
||||
Read sequentially. After each document, write a Source Document Summary (Template 1 from `templates/claude-templates.md`) to disk. Then proceed with work using summaries only.
|
||||
|
||||
## For 4+ Documents OR Any Document > 2K Words
|
||||
|
||||
**Step 1:** List all documents with file sizes. Present to user for prioritization.
|
||||
|
||||
**Step 2:** Process each document individually:
|
||||
- Read one document
|
||||
- Extract into Source Document Summary format
|
||||
- Write to `./docs/summaries/source-[filename].md`
|
||||
- Release the document from active consideration before reading the next
|
||||
|
||||
**Step 3:** After all documents are processed, read only the summaries to form your working context.
|
||||
|
||||
**Step 4:** Cross-reference summaries for contradictions or dependencies. Note these explicitly.
|
||||
|
||||
**Step 5:** Proceed with the actual task using summaries as your reference.
|
||||
18
docs/context/subagent-rules.md
Normal file
18
docs/context/subagent-rules.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Subagent Deployment Rules
|
||||
|
||||
## When to Use Subagent vs. Main Agent
|
||||
|
||||
| Situation | Approach | Why |
|
||||
|-----------|----------|-----|
|
||||
| Reading/analyzing documents | Subagent | Keeps source content out of main context |
|
||||
| Research and competitive analysis | Subagent | Heavy reading, return summary only |
|
||||
| Writing deliverables | Main agent | Needs full decision-making context |
|
||||
| Schema/architecture design | Main agent | Needs holistic project understanding |
|
||||
| Code generation | Subagent | Isolated implementation, return result |
|
||||
| Review and QA | Subagent | Fresh perspective, no bias from writing |
|
||||
|
||||
## Output Requirements
|
||||
|
||||
Subagent output must conform to the Output Contracts in `templates/claude-templates.md`. No free-form prose returns.
|
||||
|
||||
Optimal subagent return size: 1,000-2,000 tokens of structured summary. Longer returns consume main agent context without proportional benefit.
|
||||
8
docs/planning/personas.md
Normal file
8
docs/planning/personas.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Personas
|
||||
|
||||
- BAB Member
|
||||
- Certified Skipper
|
||||
- Program Administrator
|
||||
- Boatswain
|
||||
- Volunteer
|
||||
- Instructor
|
||||
125
docs/summaries/handoff-2026-03-25-initial-setup.md
Normal file
125
docs/summaries/handoff-2026-03-25-initial-setup.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Session Handoff: oysqn.app Initial Setup
|
||||
**Date:** 2026-03-25
|
||||
**Session Duration:** ~1 hour
|
||||
**Session Focus:** Create new project oysqn.app — scaffold, schema extraction, icon copy, role-based menu
|
||||
**Context Usage at Handoff:** Medium
|
||||
|
||||
## What Was Accomplished
|
||||
|
||||
1. Created project directory `/home/ptoal/Dev/mobile-projects/oysqn.app/` and scaffolded full Nuxt 4 + Ionic Vue + PrimeVue + Supabase stack → all files listed in Files table below
|
||||
2. Installed dependencies via `yarn install --ignore-engines` (Node 20 compat issue with `rollup-plugin-visualizer@7.0.1` requiring Node >=22) → `yarn.lock` created, `.yarnrc` set with `--ignore-engines true`
|
||||
3. Extracted schema from bab-app stores and translated Appwrite model → Supabase SQL → `supabase/schema.sql`
|
||||
4. Populated full TypeScript types → `app/types/supabase.ts`
|
||||
5. Rebuilt auth store with Supabase equivalents: magic link, OTP, `hasRequiredRole()`, `fetchMember()`, `getUserNameById()` → `app/stores/auth.ts`
|
||||
6. Updated `app/app.vue` with role-based IonMenu (3 visibility tiers)
|
||||
7. Copied all icons and brand assets from bab-app → `public/icons/`, `public/`
|
||||
8. Renamed composable `useToast` → `useIonToast` to avoid conflict with PrimeVue's auto-imported `useToast` → `app/composables/useIonToast.ts`
|
||||
9. `yarn typecheck` passes with 0 errors
|
||||
|
||||
## Exact State of Work in Progress
|
||||
|
||||
- Supabase project NOT created — `.env` is empty placeholder; schema SQL exists but has not been run
|
||||
- `app/stores/boat.ts` uses `as any` cast for supabase client — placeholder until real types wired via `supabase gen types`
|
||||
- Auth store uses `as any` cast for same reason — will resolve once `supabase gen types` output replaces `app/types/supabase.ts`
|
||||
- No pages beyond skeleton `index.vue`, `login.vue`, `auth/callback.vue` — all page content is TODO
|
||||
- No `app/stores/interval.ts`, `app/stores/intervalTemplate.ts`, `app/stores/reservation.ts`, `app/stores/reference.ts` yet — to be built
|
||||
- Scheduling refactor deferred — new resource picker + booking flow design not started
|
||||
|
||||
## Decisions Made This Session
|
||||
|
||||
- USE `IonRouterOutlet` in `app.vue` instead of `<NuxtPage>` BECAUSE user decision — enables Ionic page transitions and lifecycle hooks — STATUS: confirmed
|
||||
- USE Supabase INSTEAD OF Appwrite BECAUSE user decision — new project rewrite — STATUS: confirmed
|
||||
- USE `mode: 'md'` in IonicVue plugin BECAUSE consistent cross-platform appearance for PWA — STATUS: confirmed
|
||||
- USE `@nuxtjs/supabase` module BECAUSE handles SSR-safe client creation and `useSupabaseUser()` composable automatically — STATUS: confirmed
|
||||
- NO `@ionic/vue-router` BECAUSE Nuxt manages the router; `IonRouterOutlet` from `@ionic/vue` works with standard Vue Router — STATUS: confirmed
|
||||
- USE magic link + OTP only (no password auth) BECAUSE carried forward from bab-app confirmed auth model — STATUS: confirmed
|
||||
- USE `role` column on `members` table INSTEAD OF Appwrite Teams BECAUSE Supabase native pattern; simpler RLS — STATUS: confirmed
|
||||
- USE `handle_new_user()` trigger BECAUSE auto-creates `members` row on first sign-in without extra client code — STATUS: provisional (not yet tested)
|
||||
- USE `as any` cast on `useSupabaseClient()` in stores FOR NOW BECAUSE `@nuxtjs/supabase` doesn't propagate generic Database type through PostgREST column-select type inference; will resolve after `supabase gen types` — STATUS: provisional
|
||||
- SAME IonMenu for all roles with conditional sections BECAUSE user decision — STATUS: confirmed
|
||||
- USE `.yarnrc` with `--ignore-engines true` BECAUSE Node 20 installed, `rollup-plugin-visualizer` requires Node >=22 — STATUS: confirmed
|
||||
|
||||
## Key Numbers Generated or Discovered This Session
|
||||
|
||||
- 6 tables in schema: `boats`, `members`, `interval_templates`, `intervals`, `reservations`, `reference_docs`
|
||||
- 3 menu visibility tiers: all-authenticated / isBoatswain (admin+boatswain) / isAdmin only
|
||||
- 0 TypeScript errors (`yarn typecheck` clean)
|
||||
- 31 icon/asset files copied from bab-app to `public/icons/`
|
||||
- 1 trigger in schema: `handle_new_user()` on `auth.users` insert
|
||||
|
||||
## Conditional Logic Established
|
||||
|
||||
- IF `member.role` is in `['admin', 'boatswain']` THEN `isBoatswain` is true → shows "Manage Schedule" menu item
|
||||
- IF `member.role` is `'admin'` THEN `isAdmin` is true → shows "Users" + "Manage Boats" menu items
|
||||
- IF `authStore.user` changes to non-null THEN `fetchMember()` is called → populates `member` ref → menu items become visible
|
||||
- IF `cert` in `members.certifications` matches entry in `boats.required_certs` THEN user may book that boat — ASSUMED (not yet enforced in code, logic carried from bab-app)
|
||||
- IF `interval.boat_id` matches `boats.id` THEN interval appears in that boat's resource column in FullCalendar (scheduling refactor — deferred)
|
||||
|
||||
## Files Created or Modified
|
||||
|
||||
| File Path | Action | Description |
|
||||
|-----------|--------|-------------|
|
||||
| `package.json` | Created | Nuxt 4 + @ionic/vue + primevue + @nuxtjs/supabase + @pinia/nuxt + @vite-pwa/nuxt |
|
||||
| `nuxt.config.ts` | Created | Nuxt config: SSR=false, PrimeVue OYS theme (#027be3), PWA manifest, Ionic CSS |
|
||||
| `tsconfig.json` | Created | Extends `.nuxt/tsconfig.json` |
|
||||
| `.gitignore` | Created | Standard Nuxt gitignore |
|
||||
| `.env.example` | Created | `SUPABASE_URL` + `SUPABASE_KEY` placeholders |
|
||||
| `.yarnrc` | Created | `--ignore-engines true` for Node 20 compat |
|
||||
| `yarn.lock` | Created | Resolved dependency lockfile |
|
||||
| `supabase/schema.sql` | Created | Full Supabase schema: 6 tables, RLS policies, `handle_new_user` trigger |
|
||||
| `app/app.vue` | Created | IonApp + IonMenu (role-based) + IonRouterOutlet; fetchMember on mount/user-watch |
|
||||
| `app/plugins/ionic.client.ts` | Created | IonicVue plugin, mode: 'md' |
|
||||
| `app/middleware/auth.ts` | Created | Global Supabase auth guard via `useSupabaseUser()` |
|
||||
| `app/stores/auth.ts` | Created | Full auth store: role, isAdmin, isBoatswain, fetchMember, sendMagicLink, sendOtp, verifyOtp, getUserNameById, signOut, updateName |
|
||||
| `app/stores/boat.ts` | Created | Skeleton boat store with placeholder types |
|
||||
| `app/types/supabase.ts` | Created | Full Database type: 6 tables + MemberRole, ReservationStatus, Defect, TimeTuple |
|
||||
| `app/composables/useIonToast.ts` | Created | Ionic toastController wrapper (renamed from useToast to avoid PrimeVue conflict) |
|
||||
| `app/pages/index.vue` | Created | Skeleton home page (IonPage shell) |
|
||||
| `app/pages/login.vue` | Created | Skeleton login page |
|
||||
| `app/pages/auth/callback.vue` | Created | Supabase auth callback page |
|
||||
| `CLAUDE.md` | Created | Project-specific instructions for new stack |
|
||||
| `docs/planning/personas.md` | Created | Copied from bab-app |
|
||||
| `docs/context/archive-rules.md` | Created | Copied from bab-app |
|
||||
| `docs/context/processing-protocol.md` | Created | Copied from bab-app |
|
||||
| `docs/context/subagent-rules.md` | Created | Copied from bab-app |
|
||||
| `templates/claude-templates.md` | Created | Copied from bab-app |
|
||||
| `public/icons/` | Created | 31 icon/asset files copied from bab-app |
|
||||
| `public/favicon.ico` | Created | Copied from bab-app |
|
||||
| `public/oysqn_logo.png` | Created | Copied from bab-app |
|
||||
| `public/oysqn_logo_only.png` | Created | Copied from bab-app |
|
||||
| `public/oys_lighthouse.jpg` | Created | Copied from bab-app |
|
||||
|
||||
## What the NEXT Session Should Do
|
||||
|
||||
1. **First**: Create Supabase project at supabase.com; copy URL + anon key to `.env`
|
||||
2. **Then**: Run schema: paste `supabase/schema.sql` into Supabase SQL editor and execute
|
||||
3. **Then**: Run `npx supabase gen types typescript --project-id YOUR_ID > app/types/supabase.ts` to replace placeholder types and remove `as any` casts
|
||||
4. **Then**: Implement `app/pages/login.vue` — OTP flow: email input → sendOtp() → token input → verifyOtp() → redirect to `/`
|
||||
5. **Then**: Implement `app/pages/auth/callback.vue` — handle magic link redirect (Supabase sets session from URL hash)
|
||||
6. **Then**: Run `yarn dev` and verify IonRouterOutlet renders, menu appears, auth redirect fires
|
||||
7. **Then**: Build remaining stores: `reservation.ts`, `interval.ts`, `intervalTemplate.ts`, `reference.ts`
|
||||
|
||||
## Open Questions Requiring User Input
|
||||
|
||||
- [ ] Supabase project ID — needed before types, schema, and `.env` can be configured
|
||||
- [ ] Scheduling refactor design — should new resource picker and booking flow be designed before or after auth + boat pages are implemented?
|
||||
- [ ] Should `members.role` ever be set to something other than `'member'` automatically, or is role assignment always manual (admin sets it)?
|
||||
|
||||
## Assumptions That Need Validation
|
||||
|
||||
- ASSUMED: `handle_new_user()` trigger correctly fires on Supabase magic link / OTP first sign-in — validate by creating a test user and checking `members` table
|
||||
- ASSUMED: `IonRouterOutlet` in `app.vue` works without `<NuxtLayout>` wrapper in Nuxt 4 — validate at `yarn dev`
|
||||
- ASSUMED: `useSupabaseUser()` watcher in `app.vue` fires after OTP verification completes — validate in auth flow test
|
||||
- ASSUMED: cert matching logic (`members.certifications` vs `boats.required_certs`) carried forward as string array comparison — validate against domain rules in `docs/planning/`
|
||||
|
||||
## What NOT to Re-Read
|
||||
|
||||
- `docs/archive/handoffs/handoff-2026-03-25-project-scaffold.md` — superseded by this handoff
|
||||
- bab-app stores — schema extraction complete; source of truth is now `supabase/schema.sql` + `app/types/supabase.ts`
|
||||
|
||||
## Files to Load Next Session
|
||||
|
||||
- `supabase/schema.sql` — if modifying schema before running it
|
||||
- `app/stores/auth.ts` — when implementing login page
|
||||
- `app/pages/login.vue` — primary implementation target
|
||||
- `app/types/supabase.ts` — after regenerating from real Supabase project
|
||||
Reference in New Issue
Block a user