Pabal is a mobile-web-first network companion for consultants and relationship-driven professionals.
The application helps users:
- manage people and company records;
- capture meeting notes and voice updates;
- structure relationship intelligence with AI;
- track follow-ups and commitments;
- track manual needs, capabilities, and introduction opportunities;
- prepare for meetings using relationship memory;
- maintain a migration-ready SaaS foundation.
The product and engineering source of truth is:
Codex and all contributors must also follow and read carefully before any edits:
AGENTS.md/docs/development/codex-operating-model.md/docs/development/initial-codex-task.md- ADRs in
/docs/decisions
Initial V1 target:
Next.js App Router + TypeScript
PostgreSQL + Prisma
OpenAI provider adapter for AI and transcription
Hosted initially on Vercel + Neon
Migration-ready for Azure Container Apps + Azure Database for PostgreSQL
- Mobile web is the primary UX.
- Desktop is secondary and used for heavier management workflows.
- AI can propose updates but must not mutate core records without user confirmation.
- LinkedIn integration is manual user-provided enrichment only.
- The app must remain portable and Docker-compatible.
- External providers must be accessed through internal adapters.
Use the task in:
Do not ask Codex to build the full application in one step.
If uploading this pack manually through GitHub, upload the full folder contents to the root of the Creaboobot/Pobal repository and commit them. Then start Codex with the prompt in FIRST_CODEX_PROMPT.md.
This repository contains the foundation scaffold plus the Step 3 SaaS
foundation: Auth.js-compatible authentication wiring, tenants/workspaces,
memberships, roles, protected route shells, and audit logging baseline. It also
includes the Step 4A relationship backbone models and the Step 4B-1
action/intelligence-readiness models for tasks, commitments, needs,
capabilities, and introduction suggestions. It also includes Step 4B-2
schema/readiness models for AI proposals and voice notes. Step 5 adds the
mobile-first authenticated app shell for Today, Capture, People,
Opportunities, and Search. Step 6A adds the first real
product workflow: mobile-first people and company record management. Step 6B
adds basic affiliation management and read-only related meeting/note summaries.
Step 7A adds manual meeting records, meeting participants, source metadata, and
audit-logged archive/remove actions. Step 7B adds manual note workflows and
pasted Teams/Copilot meeting-note capture as user-provided text only. Step 8A
adds manual follow-up task workflows and Today task sections. Step 8B adds the
manual commitment ledger and Today commitment sections. Step 9 adds the
status-only AI proposal confirmation framework. Step 10A-1 adds manual needs
and capabilities under Opportunities. Step 10A-2 adds manual introduction
suggestion workflows. Step 10B-1 adds deterministic read-only relationship
health and why-now signals for Today and person/company detail pages. Step 10C
adds deterministic read-only meeting prep briefs from existing records. Step
11A-1 adds the backend speech-to-text provider boundary and
POST /api/voice-notes/transcribe for tenant-validated VoiceNote transcript
persistence. Step 11A-2 adds the mobile browser voice recorder, transcript
review pages, edit/archive actions, and source-context chips while keeping raw
audio out of storage. Step 11B adds review-only VoiceNote transcript
structuring into AIProposal and AIProposalItem records through a provider
adapter. Step 12A adds Microsoft Graph readiness with a protected integrations
settings page, disabled/mock provider boundary, and optional environment
variable documentation. Step 12B adds manual LinkedIn URL fields and
user-provided LinkedIn-context notes. Step 13A adds workspace admin settings,
member role/status controls, and read-only feature readiness cards using the
existing tenant, membership, and role models. Step 13B adds billing readiness
with a disabled/mock provider boundary and a read-only billing settings page.
Step 14A adds a tenant-scoped, read-only governance and audit log viewer for
workspace admins. Step 14B adds tenant-scoped JSON data exports and a privacy
settings overview. Step 14C adds owner/admin archive browsing, restore controls,
and read-only retention visibility without permanent deletion. It does not
implement AI proposal application, VoiceMention extraction, target record
mutation, live billing, live Microsoft Graph, LinkedIn automation, semantic
search, embeddings, matching, scoring, notifications, reminders, background
jobs, automatic task creation, deletion workflows, retention jobs, CSV/ZIP
exports, message drafting, outreach sending, or production deployment.
- Node.js
22.13.1from.node-version/.nvmrc - pnpm
9.15.4frompackageManager - Docker and Docker Compose for local PostgreSQL
pnpm install
Copy-Item .env.example .env.local
docker compose up -d postgres
pnpm prisma:generate
pnpm prisma:deploy
pnpm prisma:seed
pnpm prisma:validate
pnpm devEdit .env.local before starting the app:
- set
AUTH_SECRETto a local random value; - for example, run
pnpm exec auth secretafter dependencies are installed; - set
ENABLE_DEV_AUTH=trueonly for local development sign-in; - set
SEED_DEMO_DATA=truebeforepnpm prisma:seedwhen preparing a local V1 review workspace; - set
OPENAI_API_KEYonly when testing runtime OpenAI transcription; - use
SPEECH_TO_TEXT_PROVIDER=mockonly for explicit local/test mock transcription; - use
TRANSCRIPT_STRUCTURING_PROVIDER=mockonly for explicit local/test transcript structuring; - keep Microsoft Entra variables blank until OAuth is intentionally configured.
- keep
MICROSOFT_GRAPH_PROVIDER=disabledunless explicitly running local/test readiness checks; Microsoft Graph OAuth, tokens, sync, and ingestion are not implemented.
The app runs at http://localhost:3000. Development sign-in is available at
/sign-in only when ENABLE_DEV_AUTH=true and NODE_ENV is not production.
Signed-in users land on /today; unauthenticated access to /today,
/capture, /commitments, /meetings, /notes, /tasks, /people,
/proposals, /opportunities, /voice-notes, /search, /account, and
/settings redirects to /sign-in.
The primary mobile navigation is:
/today/capture/people/opportunities/search
These screens are mobile-first product surfaces backed by tenant-scoped services. Search is structured keyword search only; it does not use semantic ranking, pgvector, embeddings, AI, external lookup, or background indexing.
People and company records are available under /people:
/peoplefor people list and person creation./people/[personId]for person detail and edit/archive actions./people/companiesfor company list and company creation./people/companies/[companyId]for company detail and edit/archive actions./people/[personId]/affiliations/newto link a person to a company./people/[personId]/affiliations/[affiliationId]/editto edit, end, or archive an affiliation./people/companies/[companyId]/affiliations/newto link an existing person to a company.
Affiliation mutations are tenant-aware, audit-logged, and use transaction-safe primary affiliation handling. Related meetings and notes are read-only summaries only. Person records can store optional LinkedIn profile and Sales Navigator URLs, validated locally without fetching LinkedIn content.
Manual meeting records are available under /meetings:
/meetingsfor the active meeting list./meetings/newfor manual meeting creation./meetings/[meetingId]for meeting detail, participant list, note count, and archive action./meetings/[meetingId]/editfor meeting edits./meetings/[meetingId]/participants/newto add a known person or snapshot participant.
Participant removal deletes only the MeetingParticipant association. It does
not delete people, companies, meetings, notes, or source references. Meeting
source options stay limited to MANUAL and TEAMS_COPILOT_PASTE; LinkedIn is
available only as a note source for user-provided context.
Manual notes are available through a lightweight index and contextual routes:
/notesfor recent tenant-scoped notes./notes/newfor a general manual note./notes/[noteId]for note detail./notes/[noteId]/editfor note edits and archive actions./meetings/[meetingId]/notes/newto add a note to an existing meeting./capture/meetingto paste user-provided Teams/Copilot meeting notes into a new meeting plus linked source note.
Pasted meeting-note capture stores the pasted text in Note.body, marks the
meeting and note with TEAMS_COPILOT_PASTE, and creates a safe NOTE -> MEETING source reference. It does not parse, summarise, extract tasks,
commitments, needs, capabilities, or create AI proposals.
Manual follow-up tasks are available under /tasks:
/tasksfor task sections grouped by overdue, due today, upcoming, open without due date, and recently completed./tasks/newfor manual task creation./tasks/[taskId]for task detail and complete/reopen/archive actions./tasks/[taskId]/editfor task edits.
Tasks can link to existing people, companies, meetings, notes, commitments, and introduction suggestions. Query-parameter context links from people, companies, meetings, and notes are convenience hints only; server actions validate all linked records inside the active workspace. Step 8A does not add reminders, notifications, background jobs, automatic extraction, AI recommendations, or the commitment-ledger UI.
Manual commitments are available under /commitments:
/commitmentsfor the commitment ledger grouped by overdue, due today, upcoming, waiting, open without due date, and recently fulfilled./commitments/newfor manual commitment creation./commitments/[commitmentId]for commitment detail and fulfil/cancel/archive actions./commitments/[commitmentId]/editfor commitment edits.
Commitments can link to existing people, companies, meetings, and notes. Linked tasks are shown read-only when an existing task references a commitment. Contextual links from people, companies, meetings, and notes preselect fields only; server actions validate all linked records inside the active workspace. Step 8B does not create tasks automatically, send reminders, run background jobs, parse notes, extract commitments, or call AI providers.
AI proposal review is available under /proposals:
/proposalsfor the proposal review inbox./proposals/[proposalId]for proposal detail, source/target context, proposal item review, safe proposed patch previews, and dismiss actions.
Proposal review is status-only in Step 9. Approving a proposal item means the user accepted it as conceptually valid. It does not apply patches, create records, call AI providers, mutate target records, send messages, or start background jobs.
VoiceNote detail can create a review-only proposal from a stored or reviewed
transcript. The action asks for confirmation before sending transcript text to
the configured transcript-structuring provider, then redirects to
/proposals/[proposalId]. Provider output is strict-schema validated and entity
resolution is tenant-local only. The flow creates AIProposal and
AIProposalItem rows only; it does not apply patches, mutate targets, create
voice mentions, perform external lookup, or access LinkedIn/Microsoft/Teams/
Outlook services.
Voice notes are available through a lightweight transcript-review index and detail/edit routes:
/voice-notesfor recent tenant-scoped voice notes./voice-notes/[voiceNoteId]for voice note detail and proposal creation./voice-notes/[voiceNoteId]/editfor title, reviewed transcript, and context edits.
Microsoft integration readiness is available under settings:
/settings/integrationsfor a readiness-only Microsoft Graph card.
The page shows future calendar, selected email context, and contact capabilities, but it does not start OAuth, store tokens, call Microsoft Graph, run sync jobs, or import calendar, email, or contact data.
Manual LinkedIn enrichment is also visible on /settings/integrations and
person detail pages. Users may store LinkedIn/Sales Navigator URLs and create
LINKEDIN_USER_PROVIDED notes from manually pasted context. Pabal does not
scrape, preview, fetch, monitor, automate, sync, call LinkedIn APIs, or use
LinkedIn cookies/sessions.
Workspace administration is available under settings:
/settings/workspacefor workspace name/details and safe tenant metadata./settings/membersfor tenant-scoped member cards, role badges, owner-only role updates, and membership activation/deactivation./settings/featuresfor read-only feature readiness cards./settings/billingfor read-only billing readiness./settings/governancefor owner/admin audit log review and governance overview cards./settings/privacyfor tenant-scoped JSON exports and privacy-control visibility./settings/archivefor owner/admin archived-record browsing, restore controls, and read-only voice retention information.
Billing readiness uses a disabled provider by default and a mock provider for local/test verification only. It does not add a Stripe provider, Stripe SDK, billing schema, checkout, billing portal, webhooks, payment collection, card storage, plan gates, lockouts, quotas, entitlements, email invitations, invite tokens, or complex RBAC.
Governance uses tenant-scoped audit reads with sanitized metadata previews. It does not mutate audit rows, write audit logs for viewing, expose raw metadata, export data, delete records, enforce retention, send alerts, or integrate with SIEM tools.
Privacy exports are available under /settings/privacy. Personal export means
the current user's contribution inside the active workspace. Workspace export
requires owner/admin access and includes tenant-owned records. Exports are
single JSON downloads with no-store headers; raw audio, Auth.js tokens,
provider payloads, environment values, and raw audit metadata are excluded.
Exports may contain sensitive relationship intelligence such as note bodies,
voice transcripts, and AI proposal patches. Archive controls are available
under /settings/archive; permanent deletion, erasure automation, and
retention jobs are not implemented. The privacy copy is product guidance rather
than legal advice.
Archive controls are available under /settings/archive for workspace
owners/admins. Archive is reversible for supported archivedAt records and is
not permanent deletion. Restoring a person whose stored relationship status is
ARCHIVED maps that status to UNKNOWN because the previous status is not
stored. Archived records may still appear in exports when in scope. Raw audio is
not retained by default; VoiceNote retention metadata is read-only in this step.
Manual relationship intelligence is available under /opportunities:
/opportunitiesfor the manual intelligence hub./opportunities/needsfor need records./opportunities/needs/newfor manual need creation./opportunities/needs/[needId]for need detail and archive actions./opportunities/needs/[needId]/editfor need edits./opportunities/capabilitiesfor capability records./opportunities/capabilities/newfor manual capability creation./opportunities/capabilities/[capabilityId]for capability detail and archive actions./opportunities/capabilities/[capabilityId]/editfor capability edits./opportunities/introductionsfor manual introduction suggestions./opportunities/introductions/newfor manual introduction creation./opportunities/introductions/[introductionSuggestionId]for introduction detail, archive, and dismissal actions./opportunities/introductions/[introductionSuggestionId]/editfor introduction edits.
Needs can link to people, companies, meetings, and notes. Capabilities can link
to people, companies, and notes; the current schema has no direct meeting link
for capabilities. Introduction suggestions can link to needs, capabilities,
from/to people, and from/to companies. Meeting and note provenance is recorded
through tenant-validated SourceReference rows where provided. Contextual
create links are convenience hints only, and server actions validate all linked
records inside the active workspace. Step 10A does not add matching, scoring,
AI generation, message drafting, outreach sending, semantic search, embeddings,
notifications, jobs, or permanent deletion.
Deterministic relationship health is visible on /today, person detail pages,
and company detail pages. Signals are computed at read time from existing
tenant-scoped records such as tasks, commitments, meetings, notes, needs,
capabilities, introductions, and proposal review records. They are explainable,
source-linked where possible, and are not persisted as scores. They do not call
AI providers, create recommendations automatically, send notifications, or run
background jobs.
Meeting prep briefs are available at /meetings/[meetingId]/prep from meeting
detail. Briefs aggregate existing tenant-scoped meeting, participant, company,
note, task, commitment, need, capability, introduction, proposal, and
relationship-health context. They are deterministic, source-linked, read-only,
not AI-generated, and not synced from Outlook or Teams.
pnpm check
pnpm build
pnpm start
pnpm lint
pnpm typecheck
pnpm test
pnpm test:unit
pnpm test:integration
pnpm test:e2e
pnpm audit:prod
pnpm prisma:generate
pnpm prisma:validate
pnpm prisma:migrate
pnpm prisma:deploy
pnpm prisma:seedOptional deterministic demo data can be seeded by setting
SEED_DEMO_DATA=true before pnpm prisma:seed. The V1 review seed creates a
coherent fake workspace with people, companies, affiliations, meetings, pasted
Teams/Copilot notes, manual LinkedIn-context notes, tasks, commitments,
opportunities, introduction suggestions, review-only AI proposals, voice notes,
source references, archived records, and safe audit events. It is deterministic
and idempotent, uses only synthetic .example-style data, does not store raw
audio, and does not call AI, transcription, Microsoft, LinkedIn, billing, or
other external providers.
pnpm test:e2e runs the signed-in mobile Playwright smoke suite. It starts the
app with development auth enabled for the test server only, signs in as the
seeded demo@pobal.local reviewer, and checks the V1 review-critical routes
against deterministic demo data. Development auth remains disabled in
production, and the e2e suite uses mock/disabled provider settings so no real
OpenAI, Microsoft, LinkedIn, Stripe, or other external calls are made.
Verify the Compose file and PostgreSQL health path:
docker compose config
docker compose up -d postgres
docker compose ps
docker compose down -vStart PostgreSQL and the app:
docker compose up --buildRun migration or seed commands against the local PostgreSQL service:
docker compose run --rm migrate
docker compose run --rm seedGET /api/healthreturns a basic service health payload.GET /api/readyvalidates runtime readiness and returns503when required runtime values such asDATABASE_URLorAUTH_SECRETare missing.