1 line
11 KiB
JSON
1 line
11 KiB
JSON
{"repo": "adme-dev/dashboard", "files": {"README.md": {"9b9c48d2c8622ab049d28e6f7d63f2685543c639": {"t": 1785596458.4838586, "n": 10672, "h": "89db6cfa668779eb", "c": "# XeroFlow Agency\n\n[](https://ui.nuxt.com)\n\nInternal operations dashboard for a digital marketing agency. Manages work (boards, Kanban, timeline, calendar), clients, projects, financials (Xero integration, EOM invoicing, ad spend tracking), real-time chat, AI-powered insights, and a client portal.\n\n## Project Links\n\n- Source repository: https://github.com/adme-dev/dashboard\n- Project purpose: [docs/project-purpose.md](docs/project-purpose.md)\n- Graphify architecture artifacts: [docs/graphify.md](docs/graphify.md)\n\n## Feature Highlights\n\n- **Work Management** — Monday.com-style boards with 20+ column types, Kanban, timeline, calendar, and gallery views. Groups, subtasks, real-time collaboration via Durable Objects.\n- **Client & Project Management** — Client records, briefs, proofs, intake forms, approval workflows, and a dedicated client portal with permission-gated access.\n- **Financial Operations** — Xero OAuth integration (invoices, expenses, P&L), cashflow forecasting, end-of-month invoice generation engine with Xero upload.\n- **Ad Spend Tracking** — Meta Ads and Google Ads integrations with OAuth connections, daily/campaign spend syncing, and budget management.\n- **Real-Time Chat** — Channels, DMs, threads, file sharing, emoji reactions, pins, presence indicators, read receipts, Cmd+K switcher, and board/task integration.\n- **AI Features** — Groq-powered chat with @entity mentions, proactive anomaly detection (8 analyzers), intent classification, Vectorize semantic search, LoRA adapter management, and training data pipeline.\n- **Time Tracking** — Task-level time logging, weekly timesheets, and manager approval workflows.\n- **Smart Watch & Notifications** — Board / item / column subscriptions with reason tags, AI-prioritised inbox, daily digest narrative (Groq), snooze, quiet hours, semantic keyword subscriptions (Vectorize), auto-watch on participation, auto-acknowledge for assignments, plus email templates (Resend) and automation recipes.\n- **Client Portal** — Separate auth system with cookie-based sessions, permission-gated views for projects, approvals, invoices, and gallery.\n\n## Tech Stack\n\n### Frontend\n- Nuxt 4 (Vue 3, Composition API, `<script setup>`, TypeScript)\n- Nuxt UI v4 — component library\n- VueUse — utility composables\n- Unovis — charts and data visualisation\n- Lucide icons via `@iconify-json/lucide`\n- date-fns v4 + `@internationalized/date`\n\n### Backend (Nitro)\n- Neon Serverless Postgres (`@neondatabase/serverless`)\n- Xero API (`xero-node`) — accounting integration\n- Meta Graph API + Google Ads REST API — ad platform spend\n- Resend — transactional email\n- Groq SDK — AI/LLM features\n- Zod — runtime validation\n\n### Infrastructure (Cloudflare)\n- **Cloudflare Pages** — hosting (`nitro.preset: 'cloudflare_pages'`)\n- **Cloudflare R2** — object storage (file uploads, exports)\n- **Cloudflare Workers** — edge functions (email worker, queue consumer)\n- **Cloudflare Workflows** — durable automation for scheduled publishing and retry-sensitive orchestration\n- **Cloudflare KV** — edge caching for tokens, sessions, reports\n- **Cloudflare Queues** — background job processing with retry and DLQ\n- **Cloudflare Durable Objects** — real-time chat rooms and board events\n- **Cloudflare AI** — edge inference (`@cf/meta/llama-3.1-8b-instruct`)\n- **Cloudflare Vectorize** — semantic search index\n- **Wrangler CLI** — deploy tooling\n\n## Project Structure\n\n```\napp/\n components/ # Auto-imported Vue components (nested folders become prefixes)\n composables/ # Auto-imported composables (useFetch, useAuth, useChat, etc.)\n layouts/ # Page layouts (agency.vue, portal.vue)\n middleware/ # Route middleware (auth.global.ts, portal-auth.ts)\n pages/ # File-based routing\n agency/ # Staff-facing pages (boards, clients, chat, AI, time tracking)\n portal/ # Client portal pages (projects, approvals, invoices)\n auth/ # Authentication pages\n types/ # TypeScript types (index.ts for runtime, index.d.ts for extended)\nserver/\n api/\n agency/ # Staff API endpoints (JWT auth via requireAuth)\n portal/ # Client API endpoints (cookie auth via requireClientAuth)\n database/\n schema*.sql # Base schema files (~28 domain schemas)\n migrations/ # Numbered migrations (001–025)\n utils/ # Server utilities (db.ts, auth.ts, clientAuth.ts, etc.)\nworkers/\n ai-agent-worker/ # Proactive AI analysis worker\n board-events/ # BoardRoom Durable Object (real-time board collaboration)\n chat-rooms/ # ChatRoom Durable Object (real-time chat)\n email-worker/ # Inbound email processing (Cloudflare Email Routing)\n agency-workflows/ # Durable Cloudflare Workflows orchestration\n```\n\n## Getting Started\n\n### Prerequisites\n\n- Node.js 24.x (see `.nvmrc`)\n- pnpm >= 10\n- Xero developer account with an OAuth 2.0 app configured\n- Neon Postgres database\n\n### Clone & Install\n\n```bash\ngit clone https://github.com/adme-dev/dashboard.git\ncd dashboard\npnpm install\ncp .env.example .env\n```\n\nPopulate `.env` with the values described below.\n\n### Required Environment Variables\n\n| Variable | Description |\n| --- | --- |\n| `DATABASE_URL` | Neon Postgres connection string |\n| `XERO_CLIENT_ID` | OAuth client ID from Xero developer portal |\n| `XERO_CLIENT_SECRET` | OAuth client secret |\n| `XERO_REDIRECT_URI` | Callback path (`/api/xero/callback`) |\n| `SESSION_SECRET` | Random string for cookie/session signing |\n| `GROQ_API` | Groq API key for AI features |\n| `RESEND_API_KEY` | Resend API key for transactional email |\n| `EMAIL_FROM` | Sender address for outbound email |\n| `APP_URL` | Application URL (`http://localhost:3000` for dev) |\n\nOptional variables for Cloudflare services (R2, KV, Queues, AI, Vectorize) are documented in `.env.example`. Local dev works without them via graceful degradation.\n\n### Database Setup\n\nRun the base schema followed by migrations against your Neon database:\n\n```bash\n# Run base schema (start with schema.sql, then domain schemas as needed)\npsql $DATABASE_URL -f server/database/schema.sql\n\n# Run migrations in order\npsql $DATABASE_URL -f server/database/migrations/001-board-groups.sql\n# ... through 025-ai-chat-pins.sql\n```\n\n### Run Locally\n\n```bash\npnpm dev\n```\n\nThe app starts on http://localhost:3000. Cloudflare bindings (KV, Queues, AI, Vectorize, Durable Objects) are optional in dev — features degrade gracefully when unavailable.\n\n### Scripts\n\n| Command | Description |\n| --- | --- |\n| `pnpm dev` | Start dev server on port 3000 |\n| `pnpm build` | Production build (uses `--max-old-space-size=8192`) |\n| `pnpm preview` | Preview production build locally |\n| `pnpm test` | Run Vitest tests |\n| `pnpm lint` | Lint with ESLint |\n| `pnpm typecheck` | Run Nuxt type checking |\n| `pnpm graphify:rebuild` | Rebuild local Graphify architecture artifacts |\n| `pnpm readiness:agency-workflows` | Run Workflows cutover readiness checks |\n\n## Deploying to Cloudflare Pages\n\nThe project is configured for Cloudflare Pages via `wrangler.toml`.\n\n1. Connect the repo in the Cloudflare dashboard under **Workers & Pages > Create > Pages > Connect to Git**.\n2. Set build command to `pnpm build` and output directory to `dist`.\n3. Add environment variables in **Settings > Variables and Secrets** for both preview and production.\n4. Cloudflare bindings (KV, Queues, AI, Vectorize, Durable Objects) are configured in `wrangler.toml`.\n5. To deploy from the CLI, use the guarded repository command:\n\n ```bash\n pnpm deploy:production\n ```\n\n Do not run a raw `wrangler pages deploy` command from this repository. The guarded command verifies that both the repository configuration and deployment target are exactly `agency-dashboard`; it refuses any other Pages project. See [the Pages cross-deployment incident](docs/incidents/2026-07-13-dealer-network-pages-cross-deployment.md).\n\n### Cloudflare Bindings Setup\n\n```bash\n# KV namespace for caching\nnpx wrangler kv namespace create CACHE\n\n# Queue for background jobs\nnpx wrangler queues create agency-jobs\nnpx wrangler queues create agency-jobs-dlq\n\n# Vectorize index for semantic search\nnpx wrangler vectorize create agency-search --dimensions=768 --metric=cosine\n```\n\nDurable Objects (ChatRoom, BoardRoom) are deployed as separate workers under `workers/`.\n\n### Workers Deployment\n\nEach worker under `workers/` has its own `wrangler.toml` and deploys independently:\n\n```bash\ncd workers/chat-rooms && npx wrangler deploy\ncd workers/board-events && npx wrangler deploy\ncd workers/email-worker && npx wrangler deploy\ncd workers/ai-agent-worker && npx wrangler deploy\n```\n\n## Key Conventions\n\n### Authentication\n\n- **Staff**: JWT-based via `requireAuth(event)` — returns `User` or throws 401. Use `requireRole(event, ['admin', 'owner'])` for RBAC.\n- **Client Portal**: Cookie-based (`client_session_token`) via `requireClientAuth(event)` — returns `ServerClientUser` with `.clientId` and `.permissions`.\n- Staff endpoints live under `server/api/agency/`, client endpoints under `server/api/portal/`.\n\n### API Patterns\n\n```ts\n// Typical API endpoint\nexport default defineEventHandler(async (event) => {\n const user = await requireAuth(event)\n const id = getRouterParam(event, 'id')\n const body = await readBody(event)\n const query = getQuery(event)\n\n const rows = await queryRows('SELECT ...', [id])\n return rows\n})\n```\n\n### Server Imports\n\nServer utilities use the Nitro double-tilde alias:\n\n```ts\nimport { queryRows } from '~~/server/utils/db' // correct\nimport { queryRows } from '~/server/utils/db' // wrong\n```\n\n### Frontend Data Fetching\n\n```ts\n// Reads (reactive, SSR-compatible)\nconst { data } = await useFetch('/api/agency/tasks')\n\n// Mutations\nawait $fetch('/api/agency/tasks', { method: 'POST', body: { ... } })\n\n// User feedback\nconst toast = useToast()\ntoast.add({ title: 'Saved', color: 'success' })\n```\n\n### Types\n\nTypes must be defined in `app/types/index.ts` (not `.d.ts`) to be importable at runtime. TypeScript resolves `.ts` over `.d.ts`.\n\n## Known Issues\n\n- **Build OOM**: `nuxi build` can crash with memory exhaustion. The build script already uses `--max-old-space-size=8192` but may still fail on constrained machines.\n- **Pre-existing TS errors**: ~60+ type errors exist in components that import types from `index.d.ts` instead of `index.ts`. Running `pnpm typecheck` will surface these — they don't block the build.\n\n## Credits\n\nOriginally based on the [Nuxt UI Dashboard template](https://github.com/nuxt-ui-templates/dashboard). Extended and maintained by the ADME engineering group.\n"}}}} |