Strat Planner Pro
Developer Docs
Full-stack SaaS platform for AI-powered strategic planning — built for government agencies, public sector organizations, and investment bodies. Supabase + Deno + PostgreSQL 15.
The platform guides organizations through a structured planning lifecycle:
Full strategic planning workflow combining SWOT, TOWS Matrix, Balanced Scorecard, KPI tracking, PAP management, and MEL logging — all integrated in a single data model.
Contacts, email campaigns, automation flows, and appointment scheduling — sharing the same Supabase project and authentication layer as the planning module.
| Module | Description |
|---|---|
| SWOT Analysis | Score items by impact and likelihood; AI-generated entries flagged with badge |
| Strategic Options Matrix | Auto-generate SO, ST, WO, WT strategies from SWOT data |
| Balanced Scorecard | Objectives across Financial, Customer, Internal Process, and Learning & Growth |
| KPI Tracking | Baseline → Target → Current value tracking with on-track / at-risk / delayed / completed statuses |
| PAP Management | Programs, Activities & Projects — budget, spend, progress %, and date tracking |
| MEL Logs | Monitoring, Evaluation & Learning entries linked to specific KPIs and PAPs |
viewer / editor / admin / owner roles. Plan sharing to individuals or entire organizations with permission controls.| Feature | Details |
|---|---|
| Contact Management | Email marketing opt-ins, GIN-indexed tags, e-commerce linkage via ecom_customer_id |
| Mailing Lists | Static and dynamic (filter-query based) lists |
| Email Campaigns | Full HTML + plain-text, open/click/bounce tracking, status lifecycle: draft → scheduled → sending → sent/failed |
| Automation Flows | Trigger-based steps: send_email, add_tag, add_to_list |
| Appointment Scheduling | Round-robin, class, collective, personal calendar types. Google Calendar + Calendly integrations. |
| Schema | Purpose |
|---|---|
prj_w80v7pKpQ8s2 | Main application — all planning and CRM tables |
prj_w80v7pKpQ8s2_auth | Custom auth layer — users and OAuth identities |
prj_w80v7pKpQ8s2_storage | File storage — buckets and objects |
strategy_ai_planner_schema.sql. Apply it via the Supabase CLI or paste into the SQL Editor.| Table | Description |
|---|---|
strategic_plans | Root entity. Owns all planning child records. |
swot_items | SWOT items scored by impact (1–5) and likelihood (1–5). |
strategic_options | SO / ST / WO / WT strategies derived from SWOT. |
bsc_objectives | BSC objectives by perspective with weighting. |
kpis | KPIs with baseline, target, and current values. |
paps | Programs, Activities & Projects with budget and progress %. |
mel_logs | Monitoring, Evaluation & Learning entries. |
| Table | Description |
|---|---|
organizations | Teams / agencies. |
organization_members | Role-based org membership: viewer, editor, admin, owner |
plan_shares | Grants access to a plan for a user or org. ⚠ VARCHAR(255) — see Known Issues |
plan_comments | Threaded comments on any plan item (self-referencing). |
activity_log | Immutable audit trail of plan actions. |
user_presence | Real-time active viewer/editor tracking. |
plan_templates | Reusable templates: builtin, user, shared |
template_ratings | 1–5 star ratings; one per user per template. |
| Table | Description |
|---|---|
crm_contacts | Contact records with email opt-in and e-commerce fields. Source: form, ecom, import, manual, auth. GIN-indexed tags[]. |
crm_lists | Static or dynamic (filter-query) mailing lists. |
crm_contact_lists | Many-to-many join of contacts and lists. |
crm_campaigns | Email campaigns with send/open/click metrics. Status lifecycle: draft → scheduled → sending → sent/failed |
crm_events | Per-contact engagement events: sent, opened, clicked, bounced, unsubscribed |
crm_flows | Automation flows with trigger types. |
crm_flow_steps | Ordered steps within a flow: send_email, add_tag, add_to_list |
crm_flow_logs | Execution log: executed, failed, skipped |
crm_calendars | Calendar types: personal, round_robin, class, collective. ⚠ Default TZ: America/New_York |
crm_appointments | Booked appointments with Google/Calendly sync. Sources: manual, public_link, google, calendly |
crm_calendly_connections | Encrypted Calendly OAuth credentials. Service-only — USING (false) |
action field and routes to the appropriate prompt builder. Every AI response is structured as JSON only (no markdown preamble), parsed and rendered directly by the frontend.{ "action": "generate_swot", "data": { "organization": "Bureau of Investments - MTIT", "industry": "Investment Promotion", "strategicIntent": "Attract FDI in priority sectors", "context": "Post-pandemic recovery, Islamic finance growth" }, "plan": { } // Live plan context injected by client }
Authorization header. Required env vars: GATEWAY_API_KEY, SUPABASE_URL, SUPABASE_ANON_KEY.session.user.id. References a strategic_planner_state table — see Known Issues §2.notification_preferences on the user profile — returns 200 without sending if notification type is disabled. Queries user_profiles (note: not profiles — see Known Issues §5).strategic-planner-sync.| Action | Input | Output |
|---|---|---|
generate_swot | Org context, industry, strategic intent, additional context | Scored SWOT items for all 4 quadrants |
generate_strategies | Existing SWOT items | SO / ST / WO / WT strategic options |
generate_objectives | BSC perspective, strategic goal | Suggested BSC objectives |
generate_kpis | BSC objective text | Relevant, measurable KPI suggestions |
generate_paps | Strategic objectives | Programs, Activities & Projects |
generate_insights | Current performance data | MEL insights and observations |
analyze_trends | Sector, region parameters | Investment & sector trend analysis |
suggest_archetypes | Org dynamics description | Systems thinking archetypes with confidence |
build_ccd | SWOT items + objectives | Causal loop diagram nodes and links |
analyze_loops | CLD structure | Reinforcing and balancing loop analysis |
recommend_actions | MEL insights | Prioritized action recommendations |
- Unique contacts by email address — deduplication enforced at DB level
- Source tracking:
form,ecom,import,manual,auth - GIN-indexed
tags[]array for fast tag-based filtering - E-commerce linkage:
ecom_customer_id,total_orders,total_spent
USING (true) — any authenticated user can read/write all CRM data. Scope to owner_user_id before multi-tenant production deployment. See Known Issues §1 for the fix SQL.contact.subscribed
order.placed
contact.tagged
user.registered
appointment.booked
| Feature | Detail |
|---|---|
| Calendar Types | personal, round_robin, class, collective |
| Slot Configuration | Configurable slot duration, buffer times, max bookings per day, minimum notice |
| Availability | Weekly windows per calendar (0=Sunday … 6=Saturday) |
| Appointment Sources | manual, public_link, google, calendly |
| Google Sync | Via google_refresh_token on crm_calendars |
| Calendly Integration | Encrypted OAuth tokens in crm_calendly_connections — service-role only access |
All core planning tables are scoped to the authenticated user's user_id via JWT claim:
-- Example: strategic_plans USING ((current_setting('request.jwt.claim.sub', true))::uuid = user_id)
Child tables (bsc_objectives, kpis, paps, mel_logs, swot_items) use subquery policies that verify ownership via the parent strategic_plans record.
USING (true). Acceptable for single-tenant deployment but must be scoped to owner_user_id before multi-tenant production use.-- Recommended fix example for crm_contacts CREATE POLICY "Users access own contacts" ON crm_contacts FOR ALL USING (owner_user_id = (current_setting('request.jwt.claim.sub', true))::uuid);
-- Blocks all client-side access USING (false) WITH CHECK (false)
Calendly OAuth tokens are only accessible via the service role key in Edge Functions. Tokens are stored as encrypted_access_token and signing_key — must be encrypted at the application layer before insert.
supabase secrets set KEY=value.- Supabase CLI installed — supabase.com/docs/guides/cli
- Deno v1.40+ installed — deno.land
- Supabase project created at supabase.com
strategy_ai_planner_schema.sql into the Supabase SQL Editor.supabase db push --db-url "postgresql://postgres:[PASSWORD]@[HOST]:5432/postgres" \ < strategy_ai_planner_schema.sql
supabase functions deploy ai-strategy-assistant supabase functions deploy strategic-planner-sync supabase functions deploy email-notifications supabase functions deploy cloud-sync
supabase secrets set GATEWAY_API_KEY=your_key_here supabase secrets set RESEND_API_KEY=your_key_here supabase secrets set SUPABASE_SERVICE_ROLE_KEY=your_key_here
pending-tasks for app assets.NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
USING (true). Any authenticated user can access all CRM data. If multiple organizations share this Supabase project, add an owner_user_id column and scope all CRM policies to it.
CREATE POLICY "Users access own contacts" ON crm_contacts FOR ALL USING (owner_user_id = (current_setting('request.jwt.claim.sub', true))::uuid);
strategic_planner_state Table
High Priority
strategic-planner-sync function references a strategic_planner_state table for caching full plan snapshots, but this table is absent from the current schema dump.
CREATE TABLE strategic_planner_state ( id uuid DEFAULT gen_random_uuid() PRIMARY KEY, user_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, state jsonb NOT NULL DEFAULT '{}', updated_at timestamp with time zone DEFAULT now() );
crm_calendly_connections stores encrypted_access_token and signing_key as plain text columns. Ensure tokens are encrypted at the application layer before insert — do not rely solely on Supabase's at-rest encryption.
crm_calendars defaults to America/New_York. Since this platform targets Philippine agencies, change the default to Asia/Manila.
email-notifications queries a profiles table which does not exist in the schema — user_profiles is the correct table name. Verify the function references the right table name after any migrations.
plan_shares & plan_comments — UUID vs VARCHAR
Low Priority
plan_id on plan_shares, plan_comments, activity_log, and user_presence is typed as VARCHAR(255) rather than UUID, while strategic_plans.id is a proper UUID. Align these types and add foreign key constraints for referential integrity.