279 lines
11 KiB
Markdown
279 lines
11 KiB
Markdown
# Job Info Test - Project Overview
|
|
|
|
## What is this?
|
|
|
|
**Job-Info-Test** is a modern, modular application testbed for exploring and validating:
|
|
- **Microsoft Graph API interactions** - token acquisition, caching, refresh, data queries
|
|
- **PocketBase integration** - OAuth2 flows, user management, data persistence
|
|
- **Industry-standard UI/UX patterns** - reactive components, state management, real-time updates
|
|
- **Developer experience (DX)** - clean APIs, TypeScript support, proper error handling, observability
|
|
- **Architecture best practices** - modular design, separation of concerns, testability
|
|
|
|
It uses a **Mode system** where different technology implementations can be built and tested in parallel without interfering with each other.
|
|
|
|
## Purpose
|
|
|
|
This is not just an auth test—it's a **reference implementation playground** for:
|
|
- Building **real, production-quality features** with Graph API (user data, calendar, files, etc.)
|
|
- Implementing **reactive, modern UI** with Svelte and industry best practices
|
|
- Creating **clean, maintainable code architecture** that teams can learn from
|
|
- Testing **complex workflows** combining Graph + PocketBase + custom logic
|
|
- Demonstrating **proper error handling, loading states, and data synchronization**
|
|
- Building **DX-first APIs** that are a pleasure to use and extend
|
|
|
|
## Development Standards
|
|
|
|
**These rules MUST be followed on every code change. Review before editing.**
|
|
|
|
### 1. Variable Naming — Strict Consistency
|
|
- Auth and token variable names are **NOT flexible** — they are fixed throughout the project
|
|
- Use **identical names** every time a value is referenced, passed, or used
|
|
- **Examples of correct consistency:**
|
|
- Graph token: always `graphToken` (never `graph_token`, `token`, or `accessToken`)
|
|
- PocketBase token: always `pbToken` (never `pocketbaseToken`, `pb_token`, or `userToken`)
|
|
- User ID: always `userId` (never `user_id`, `uid`, or `id`)
|
|
- Current user: always `currentUser` (never `user`, `loggedInUser`, or `authUser`)
|
|
- **Why:** Eliminates confusion about what value is being used and where it comes from
|
|
- **Enforcement:** If a variable name changes, it must change everywhere it's used in that mode
|
|
|
|
### 2. Mode Independence — Standalone Projects
|
|
- **Each mode is completely independent** — can run on any machine without parent directory
|
|
- **Copy modules in, never depend on them externally**
|
|
- If `auth-module` is used in multiple modes, copy it into each mode's directory
|
|
- Never import from `../auth-module` or `../../auth-module`
|
|
- Each mode has its own complete copy of all dependencies
|
|
- **Modes must not reference each other**
|
|
- No imports between Mode1 and Mode1Svelte
|
|
- No shared backend code between modes
|
|
- **Benefit:** Can delete, move, or duplicate a mode without breaking anything else
|
|
|
|
### 3. Development Scope — Edit Only Your Mode
|
|
- **Only edit the mode you're actively working on** — all other modes untouched
|
|
- **You can reference other modes** for patterns/examples, but don't code in them
|
|
- **Exception:** Only modify another mode if explicitly agreed upon in writing
|
|
- **Corollary:** If shared logic needs updating (like auth-module), update it in your working mode, test it, then copy it to other modes if approved
|
|
|
|
### 4. Ports — 3005 & 3006 ONLY
|
|
- **Work exclusively with ports 3005 and 3006**
|
|
- Port 3005: Active mode backend + frontend
|
|
- Port 3006: ModeSwitch orchestrator
|
|
- **Do NOT check any other ports** — ignore them entirely
|
|
- **Ignore all other running services** — focus only on these two ports
|
|
|
|
### 5. Service Restart — Kill, Then Start
|
|
- **Always assume something is running** on the port before starting
|
|
- **Always kill first, then start:**
|
|
```bash
|
|
pkill -f "bun.*server.ts" || true
|
|
sleep 1
|
|
PORT=3005 bun run backend/server.ts
|
|
```
|
|
- **This prevents port-binding conflicts** and ensures clean startup
|
|
|
|
### 6. Service Validation — One Check, Then Stop
|
|
- **Do ONE comprehensive health check after startup**
|
|
- Verify backend is listening on correct port
|
|
- Verify frontend is accessible
|
|
- Verify all critical endpoints respond (auth endpoints, health checks)
|
|
- Verify no error messages in logs
|
|
- **Then STOP checking** — if health is good, leave it running
|
|
- **Do NOT check 3, 4, or multiple times** — it wastes time and adds no value
|
|
- **If health check passes, service is ready** — move forward to next task
|
|
|
|
### 7. Git Commits & Sync — Developer Agreement Required
|
|
- **Never commit or sync without explicit developer approval**
|
|
- **Only prompt for commit/sync AFTER code verification**
|
|
- Code must be working as intended
|
|
- Tests passing (if applicable)
|
|
- Health checks passing
|
|
- Developer has confirmed the feature/fix is complete
|
|
- **Workflow:** Build → Test → Confirm Working → **Then ask about commit**
|
|
- **No automatic commits or premature prompts**
|
|
|
|
## Architecture
|
|
|
|
```
|
|
Job-Info-Test/
|
|
├── auth-module/ # Shared, reusable auth component (root copy)
|
|
├── Mode1/ # Hono + vanilla JavaScript (LOCKED/READ-ONLY reference)
|
|
├── Mode1Svelte/ # Hono + SvelteKit (active development - modern DX/UX)
|
|
├── ModeSwitch/ # Orchestrator to manage mode switching
|
|
├── Mode6Test/ # Legacy testing environment
|
|
└── README.md # This file
|
|
```
|
|
|
|
## The Mode System
|
|
|
|
Each **Mode** is a completely independent project that:
|
|
- Has its own copy of `auth-module` (no cross-dependencies)
|
|
- Runs on the same ports (3005 backend, 3006 orchestrator)
|
|
- Can be swapped via ModeSwitch without affecting others
|
|
- Shares the same secret configuration (`/home/admin/secrets/.env`)
|
|
|
|
### Current Modes
|
|
|
|
#### **Mode1** (READ-ONLY Reference Implementation)
|
|
- **Frontend:** Vanilla HTML + JavaScript
|
|
- **Backend:** Hono (TypeScript)
|
|
- **Status:** Reference implementation, locked to prevent accidental changes
|
|
- **Port:** 3005
|
|
|
|
#### **Mode1Svelte** (Active Development)
|
|
- **Frontend:** SvelteKit (Svelte components, reactive)
|
|
- **Backend:** Hono (same as Mode1)
|
|
- **Status:** Being converted to full SvelteKit following industry best practices
|
|
- **Port:** 3005
|
|
|
|
## Key Components
|
|
|
|
### Auth Module (`/auth-module/`)
|
|
Reusable authentication component with:
|
|
- **Backend** (`backend.ts`):
|
|
- `AuthConfigManager` - Loads and provides configuration
|
|
- `GraphTokenManager` - Acquires Microsoft Graph tokens via MSAL
|
|
- `PocketBaseValidator` - Validates user tokens
|
|
- `BackendAuth` - Orchestrates backend auth flow
|
|
|
|
- **Frontend** (`frontend.ts`):
|
|
- `PocketBaseAuth` - OAuth2 login/logout/state management
|
|
- `initPocketBaseAuth()` - Initialize with callbacks
|
|
|
|
- **Types** (`types.ts`):
|
|
- `FrontendConfig` - Configuration provided to frontend
|
|
- `AuthState` - Frontend authentication state
|
|
|
|
### ModeSwitch Orchestrator (`/ModeSwitch/`)
|
|
- Listens on port 3006
|
|
- Manages active mode switching via `POST /switch/:mode`
|
|
- Returns mode status and health checks
|
|
- Starts/stops backend servers as needed
|
|
|
|
## How It Works
|
|
|
|
### Startup Flow
|
|
1. **ModeSwitch starts** on port 3006 (orchestrator)
|
|
2. **Active mode backend starts** on port 3005
|
|
3. **Frontend served** at `http://localhost:3005` (or `https://ji-test.ccllc.pro`)
|
|
4. **Frontend fetches config** from `/api/auth/config`
|
|
5. **Backend loads secrets** from `/home/admin/secrets/.env`
|
|
|
|
### Auth Flow
|
|
1. **Frontend OAuth Login:**
|
|
- User clicks login button
|
|
- Browser redirected to PocketBase OAuth provider
|
|
- PocketBase returns user and token
|
|
- Frontend stores token in `pbAuth.getAuthState()`
|
|
|
|
2. **Backend Graph Token:**
|
|
- Frontend calls `/api/auth/graph/token`
|
|
- Backend uses MSAL to acquire Microsoft Graph token
|
|
- Token cached with 60-second expiration buffer
|
|
- Frontend receives token with JWT payload details
|
|
|
|
3. **Token Comparison:**
|
|
- Frontend sends PocketBase token to `/api/auth/compare-tokens`
|
|
- Backend validates PB token and decodes Graph token JWT
|
|
- Returns side-by-side comparison showing they're different systems
|
|
|
|
## Running the Project
|
|
|
|
### Via ModeSwitch (Recommended)
|
|
```bash
|
|
# Start ModeSwitch (listens on 3006)
|
|
cd /home/admin/Job-Info-Test/ModeSwitch
|
|
PORT=3006 bun run backend/orchestrator.ts
|
|
|
|
# In another terminal, switch to desired mode
|
|
curl -X POST http://localhost:3006/switch/Mode1Svelte
|
|
|
|
# Access frontend
|
|
open https://ji-test.ccllc.pro
|
|
# or
|
|
open http://localhost:3005
|
|
```
|
|
|
|
### Direct Mode Start
|
|
```bash
|
|
# Start Mode1Svelte directly
|
|
cd /home/admin/Job-Info-Test/Mode1Svelte
|
|
PORT=3005 bun run backend/server.ts
|
|
|
|
# Access frontend
|
|
open http://localhost:3005
|
|
```
|
|
|
|
## Configuration
|
|
|
|
**Secrets** (`/home/admin/secrets/.env`):
|
|
```
|
|
CLIENT_ID=<Azure app client ID>
|
|
TENANT_ID=<Azure tenant ID>
|
|
CLIENT_SECRET=<Azure app client secret>
|
|
PB_URL=<PocketBase server URL>
|
|
PB_DB=<PocketBase database name>
|
|
```
|
|
|
|
These are loaded:
|
|
- **Backend:** Automatically on server startup via `dotenv`
|
|
- **Frontend:** Via API endpoint `/api/auth/config` (no hardcoded URLs)
|
|
|
|
## Project Structure Details
|
|
|
|
### Mode1 (Reference - READ-ONLY)
|
|
```
|
|
Mode1/
|
|
├── auth-module/ # Self-contained copy
|
|
├── backend/
|
|
│ └── server.ts # Hono + auth endpoints
|
|
├── frontend/
|
|
│ ├── index.html # Test dashboard
|
|
│ └── dist/ # Built assets
|
|
└── package.json
|
|
```
|
|
|
|
### Mode1Svelte (In Development)
|
|
```
|
|
Mode1Svelte/
|
|
├── auth-module/ # Self-contained copy
|
|
├── backend/
|
|
│ └── server.ts # Hono + auth endpoints
|
|
├── src/
|
|
│ ├── routes/ # SvelteKit pages (to be added)
|
|
│ ├── lib/ # Svelte components (to be added)
|
|
│ └── app.svelte # Root component (to be added)
|
|
└── svelte.config.js # SvelteKit config (to be added)
|
|
```
|
|
|
|
## Development Notes
|
|
|
|
- **Mode1 is locked** to preserve the reference implementation
|
|
- **Mode1Svelte** is the active development branch
|
|
- Both modes can run simultaneously on different orchestrator instances
|
|
- No code dependencies between modes—each is fully independent
|
|
- Auth-module changes should be made in root `/auth-module/`, then copied to each mode
|
|
|
|
## Testing
|
|
|
|
**Dashboard at** `https://ji-test.ccllc.pro`:
|
|
- ✅ Complete auth flow (PocketBase OAuth2)
|
|
- ✅ Microsoft Graph token acquisition, caching, refresh
|
|
- ✅ Real Graph API interactions (user profile, mail, calendar, files, etc.)
|
|
- ✅ PocketBase data queries and mutations
|
|
- ✅ Token comparison and validation
|
|
- ✅ Error states and loading indicators
|
|
- ✅ Timestamped logs and observability
|
|
- ✅ Real-time data synchronization patterns
|
|
|
|
## Next Steps
|
|
|
|
1. **Convert Mode1Svelte to full SvelteKit** with modern component architecture
|
|
2. **Build Graph API features** - implement real use cases beyond auth
|
|
3. **Create reactive Svelte components** - proper state management, stores, lifecycle
|
|
4. **Add TypeScript throughout** - strict types, better DX
|
|
5. **Implement data layers** - abstracting Graph API and PocketBase queries
|
|
6. **Build responsive UI** - mobile-first design, accessibility (a11y)
|
|
7. **Add observability** - logging, error tracking, performance monitoring
|
|
8. **Create component library** - reusable, well-documented Svelte components
|
|
9. **Write comprehensive tests** - unit, integration, E2E
|
|
10. **Document patterns** - make this a reference for modern full-stack Svelte apps
|