Version: Spring 2026 Developer Reference
Last updated: 2026-04-01
- Document Purpose
- Product Overview
- Primary Product Goals
- User Roles
- Current Database Schema
- Product Logic Clarifications
- Page Specifications
- Reminder and Survey Operational Intent
- Tree Lifecycle Intent
- Export / Search / Filtering Expectations
- Known Source-of-Truth Decisions
- Suggested Developer Interpretation Guidelines
This document is the comprehensive product and implementation reference for the ECOSLO platform. It consolidates the original Spring MVP planning document, earlier sprint planning notes, and clarified product decisions discussed by the tech leads.
This document is intended for developers building the platform during Spring quarter.
- The current database schema is the source of truth for data modeling.
- The product requirements from the original PRD remain the source of truth for intended behavior.
- Where the original PRD and the current schema differ, this document resolves the discrepancy in favor of the current schema, while noting intended product behavior.
- UI mockups and early Figma designs are helpful references, but they are not the primary source of truth.
ECOSLO is a nonprofit that plants trees and maintains them around San Luis Obispo. The platform being built for ECOSLO is intended to centralize operations that are currently spread across manual processes and disconnected systems.
The platform should allow ECOSLO to:
- manage tree records
- manage members and tree keepers
- view a public tree map
- assign and track one-off tasks
- define recurring reminders
- collect surveys tied to tasks and trees
- provide a dashboard and operational workflows for admins
The platform supports both internal operations and public-facing map functionality.
The platform should eventually support the following operational areas:
-
Trees management
- create, view, edit, and delete tree records
- search, filter, sort, and export tree data
- manage tree status, condition, notes, maintenance-related data, and tree keeper assignments
-
Members management
- manage members and their contact information
- distinguish between admins and tree keepers
- track assigned trees
-
Public tree map
- expose public tree data only
- allow public browsing of visible trees
- support simple tree information viewing and issue-report workflows
-
Tasks system
- manage one-off operational tasks
- assign tasks to one or more members
- track completion status
- support survey-gated completion
-
Reminders system
- define recurring reminders
- generate recurring task-like workflows from reminder definitions
- support admin workflows for scheduling and management
-
Survey collection
- capture tree- and task-specific survey submissions
- support maintenance/status reporting tied to specific trees
- support task completion requirements where surveys are needed
-
Dashboard and internal operations
- provide an admin-facing overview of tasks, reminders, and tree activity
- surface operational priorities and recent activity
The platform currently recognizes three product-level user groups.
Admins can manage internal operations.
Expected capabilities:
- see and edit all internal data
- manage trees
- manage members
- create and manage tasks
- create and manage reminders
- view and manage surveys
- access internal dashboard pages
Tree Keepers are members who are responsible for one or more trees.
Expected capabilities:
- view tasks relevant to them
- complete visible tasks
- submit surveys related to assigned work
- view or update tree-related information that product rules permit
Public users are not authenticated internal users.
Expected capabilities:
- access the public tree map
- view public tree information only
- no access to internal admin/member/task/reminder workflows
Terminology note: this document uses Members and Tree Keepers consistently. Older planning materials used the term Volunteers. Treat that wording as legacy terminology.
The following sections reflect the current database schema and should be treated as the implementation source of truth.
ActiveGraduated
CompletedPending
CompletedPending
goodfairpoor
AdminTree Keeper
Represents all trees managed by ECOSLO.
id: bigint, primary keycreated_at: timestamptz, defaults tonow()status:TreeStatus, defaults toActiveecoslo_num: bigint, unique identity valuespecies_name: textcommon_name: textfunder: textdate_planted: dateaddress: textlatitude: float8longitude: float8is_public: boolean, defaults tofalseweekly_watering_status:WateringStatus, defaults toPendingnext_mulching_date: date, nullablenotes: text, nullable, defaults to empty stringcondition:Condition, defaults togoodnext_watering_date: date, nullableyearly_mulching_status:MulchingStatus, defaults toPendingadmin_notes: text, defaults to empty stringsurvey_logs: bigint[], nullabletree_keeper_id: bigint, nullable, foreign key tomembers.id
trees.tree_keeper_id -> members.idsurveys.tree -> trees.ecoslo_num
statusis for lifecycle state only:ActiveorGraduatedconditionis for tree health/quality state:good,fair,poornotesshould be treated as general or tree-keeper-visible notesadmin_notesis admin-only/internalsurvey_logsreferences surveys associated with the treetree_keeper_ididentifies the member currently assigned to the tree
Represents internal members, including admins and tree keepers.
id: bigint, primary keycreated_at: timestamptz, defaults tonow()firstname: textlastname: textemail: text, uniquephone: textjoined: date, defaults tonow()trees_assigned: bigint[], nullabletrees_count: bigint, defaults to0role:MemberType, nullable
Referenced by:
tasks.created_by -> members.idtrees.tree_keeper_id -> members.id
- Members replaces older
volunteersterminology roledistinguishesAdminandTree Keepertrees_assignedshould represent ECOSLO tree numbers or assigned tree references as currently implementedtrees_countis derived/supporting operational data
Represents one-off tasks assigned to one or more members.
id: bigint, primary keycreated_at: timestamptz, defaults tonow()completion_date: timestamptz, nullablemessage: texttitle: text, defaults to empty stringassignees: bigint[], nullableis_complete: boolean, defaults tofalsesurveys_needed: bigint, defaults to0created_by: bigint, nullable, foreign key tomembers.id
tasks.created_by -> members.idsurveys.task -> tasks.id
- Tasks are one-off items, not recurring schedules
- A single task may be assigned to one member or many members
- Group tasks remain a single shared task object, not duplicated tasks per assignee
surveys_neededis the current source of truth for survey gating logic
Represents survey submissions associated with a task and/or tree.
id: bigint, primary keycreated_at: timestamptz, defaults tonow()task: bigint, nullable, foreign key totasks.idtree: bigint, nullable, foreign key totrees.ecoslo_numbody: jsonb
surveys.task -> tasks.idsurveys.tree -> trees.ecoslo_num
The current survey table stores detailed survey form data inside body.
This means fields such as the following should be serialized inside body rather than expected as top-level DB columns:
- issue type
- optional
otherissue text - image link
- admin contact request / needs contact response
- any future structured survey answers
Represents recurring reminder definitions.
id: bigint, primary keycreated_at: timestamptz, defaults tonow()name: text, defaults to empty stringis_active: boolean, defaults totruecrons_expression: text, defaults to empty stringtask_message: text, defaults to empty stringassignees: bigint[]is_group_task: boolean, defaults tofalse
- Reminders define recurring operational workflows
- Reminder definitions are intended to drive future scheduled task generation
crons_expressionis the current persistence field for schedule configurationtask_messageis the template/body for the generated reminder contentassigneesstores the target member IDs for the reminder
Represents reusable reminder/task templates.
id: bigint, primary keycreated_at: timestamptz, defaults tonow()crons_expression: text, defaults to empty stringtask_message: text, defaults to empty stringassignees: bigint[]is_group_task: boolean, defaults tofalsename: text, defaults to empty string
- Templates store reusable scheduling/message definitions
- The schema is intentionally very similar to
reminders - Templates are meant to support faster creation of reminders or repeated operational workflows
members (1) ──< trees (many) via trees.tree_keeper_id → members.id
members (1) ──< tasks (many) via tasks.created_by → members.id
tasks (1) ──< surveys (many) via surveys.task → tasks.id
trees (1) ──< surveys (many) via surveys.tree → trees.ecoslo_num
This section captures clarified logic that should be treated as part of the current spec.
Tasks are one-off work items. Recurring behavior belongs to the reminders system, not the tasks page itself.
The original planning materials used both boolean-style and integer-style descriptions for whether a task needs a survey. The clarified product rule is:
tasks.surveys_needed = 0means the task does not currently require any remaining survey submissions before completiontasks.surveys_needed > 0means the task still requires survey submissions before completion- The integer field is the source of truth
- A separate boolean field is not required in the current model
- If
surveys_needed = 0, the task can be completed directly - If
surveys_needed > 0, the user should be redirected into or required to complete the survey workflow - Each valid survey submission tied to that task should decrement
surveys_neededby 1 - When
surveys_neededreaches0, the task should auto-complete - When the task auto-completes, it should set:
is_complete = truecompletion_date = current timestamp
- Group tasks remain a single shared task object
- If a group task is completed, it is completed for the whole group
- For survey-gated shared tasks,
surveys_neededrepresents the number of required remaining survey submissions for that shared task object
The current schema for public.surveys contains only:
tasktreebody
Therefore, all detailed survey response content should be stored in body.
The exact JSON structure may evolve, but it should support fields such as:
issueotherIssueTextimageLinkneedsContact- any additional structured survey responses
Example conceptual shape:
{
"issue": "Damaged bark",
"otherIssueText": "",
"imageLink": "https://...",
"needsContact": true
}All new development should use:
- Members for the overall internal user table
- Tree Keepers for the role formerly referred to as volunteers in some planning notes
Avoid introducing new volunteers naming in routes, components, or docs unless referencing legacy code that has not yet been migrated.
These fields have distinct meanings and should not be conflated.
-
status= lifecycle stateActiveGraduated
-
condition= tree condition/health stategoodfairpoor
Reminder and template behavior should be designed around the actual database schema rather than around rough UI labels alone.
name,task_message,crons_expression,assignees, andis_group_taskare the current source-of-truth fields- UI concepts like “Audience” must eventually resolve to actual stored data, primarily
assignees - UI designs are helpful references but may need to be adjusted to fit the product requirements and schema
The following sections describe intended page behavior based on the original PRD, updated to reflect the current schema and clarified logic.
Allow admins to manage tree records and inspect tree-related operational data.
- list trees
- search, filter, sort, and paginate
- export tree data
- create and edit trees
- view tree details
- delete trees where allowed
Primary source: public.trees
ecoslo_numstatusconditionspecies_namecommon_namefunderdate_plantedaddresslatitudelongitudeis_publictree_keeper_idnext_watering_dateweekly_watering_statusnext_mulching_dateyearly_mulching_statusnotesadmin_notessurvey_logs
- page header
- export CSV button
- add tree action
- control panel with:
- search
- status filters
- condition filters
- visibility filter
- tree list/table
- pagination/footer
- view/edit details panel
- Public/private visibility should be driven by
is_public - Tree keeper information should be derived via
tree_keeper_id -> members.id survey_logsmay be used later to surface survey history
Allow admins to manage internal members and tree keeper assignments.
- list members
- create new members
- edit members
- search/filter/sort/export
- distinguish roles
Primary source: public.members
firstnamelastnameemailphonejoinedroletrees_assignedtrees_count
- page header
- export CSV button
- add member action
- control panel with search and role filtering
- members list/table
- pagination/footer
- view/edit details panel
Allow internal users to view and manage one-off tasks.
Primary source: public.tasks
idcreated_attitlemessageassigneesis_completecompletion_datesurveys_neededcreated_by
- can view all tasks
- can create tasks
- can complete tasks
- can sort/filter tasks
- should only see tasks assigned directly to them or shared tasks that include them
- can complete visible tasks
- should not see unrelated tasks
- no access
The original PRD described a table-like tasks page, but current design work is trending toward a card-based task list with top filters. The exact final UI can evolve, but it must support the same underlying product behavior.
- search tasks
- filter by completion status
- filter by assignee
- filter by survey requirement
- browse open tasks by default
- inspect task details
- complete tasks
- if
surveys_needed = 0, allow direct completion - if
surveys_needed > 0, direct the user into survey submission flow - after the final required survey is submitted, auto-complete the task
assigneesis stored as a bigint array of member IDs- any assignee-facing display may require member lookup/formatting
- completed tasks may later be cleaned up or expired, but that is not currently encoded in schema
Allow admins to view, create, edit, activate/deactivate, and delete recurring reminders.
Primary source: public.reminders
Secondary supporting source: public.templates
idcreated_atnameis_activecrons_expressiontask_messageassigneesis_group_task
idcreated_atnamecrons_expressiontask_messageassigneesis_group_task
- list existing reminders
- inspect a selected reminder
- create a new reminder
- edit an existing reminder
- delete a reminder
- toggle active/inactive state
- edit scheduling fields
- edit message template content
- reminders are definitions for recurring workflows
- reminders should be admin-managed
- reminder schedule data ultimately persists into
crons_expression - reminder target members persist into
assignees - reminder message content persists into
task_message - templates should support reusable reminder/task configuration
Some designs may use labels like:
- Type
- Audience
- Schedule
- Next Send
These can be valid UI affordances, but the backing persistence should still be aligned to the actual schema.
Allow users to submit structured survey information tied to a task and tree.
Primary source: public.surveys
Supporting sources:
public.taskspublic.trees
Each created survey should be able to persist:
task: selectedtasks.idtree: selectedtrees.ecoslo_numbody: structured survey content
The form should be able to collect and store fields such as:
- issue type
- optional custom issue text
- image link
- needs contact / admin contact response
- submitting a survey should create a
surveysrow - the survey should be tied to the relevant task and tree
- valid task-linked survey creation should decrement
tasks.surveys_needed - when
tasks.surveys_neededreaches0, the task should auto-complete
- select task
- select tree
- select issue type
- optionally provide other issue text
- optionally provide image link
- indicate whether admin follow-up/contact is needed
- submit successfully with clear feedback
Expose public tree information to non-authenticated users.
Public-safe subset of public.trees
At minimum, the public map should only expose non-sensitive tree/location metadata required for display, such as:
- tree identifier
- latitude/longitude
- species/common names
- date planted
- public-safe tree keeper naming only if explicitly intended
ecoslo_numstatusis_public
- render map and markers
- allow marker selection
- show public tree info panel
- support map searching/filtering
- preserve privacy for non-public/internal-only data
Support authenticated access for internal users.
- login page with email entry
- magic link flow
- auth callback handling
- session-aware routing
- route protection for internal pages
The original planning notes referenced Supabase-based magic-link auth and SSR/callback/session work. Exact implementation may continue evolving, but auth pages should support internal member access cleanly.
Provide a high-level operational overview for internal users, especially admins.
- tasks
- reminders
- trees
- tasks widget
- reminders widget
- trees widget
- navigation into full page flows
Dashboard implementation can follow after core operational pages are established.
The original PRD emphasized a strong relationship between recurring reminders, task generation, and survey collection.
The intended long-term operational flow is:
- Admin defines reminder/template behavior
- Reminder schedule triggers recurring task-like work
- Users receive and complete work
- Some tasks require one or more survey submissions
- Survey submissions update tree/task operational state
Not all of this workflow is fully encoded in the current schema or current sprint scope, but it remains part of the product direction.
The original PRD specified tree lifecycle concepts such as:
- trees graduating after three years
- recurring watering/mulching/pruning/check-in logic
- alerts before graduation
The current schema partially supports maintenance tracking through:
statusnext_watering_dateweekly_watering_statusnext_mulching_dateyearly_mulching_status
Additional lifecycle automation may be implemented later, but these concepts remain important to the product direction.
Across internal management pages, the general product expectation is:
- searchable data lists
- useful filters tied to actual schema fields
- paginated or otherwise navigable result sets
- export support for operational/admin use
These capabilities apply most strongly to:
- Trees
- Members
- Tasks
These decisions should be treated as authoritative for current development.
- Use current DB schema as source of truth
- Task survey gating uses
tasks.surveys_needed - Tasks auto-complete when
surveys_neededreaches 0 after valid survey submission - Detailed survey response content lives in
surveys.bodyJSON - Use
MembersandTree Keepersterminology, notVolunteers - UI designs are helpful references, but schema + product requirements take precedence
When there is ambiguity, developers should follow this order of precedence:
- Current database schema
- Clarified product rules in this document
- Original PRD behavior intent
- Existing codebase conventions
- Figma/UI mocks