Core Concepts
FlagPulse's data model has five entities, each with a foreign-key chain down to the next.
users ──< projects ──< environments
│ │
└──< flags ──< flag_values >──┘
│
└──< audit_logs >── environments / flagsUsers
A user registers with a name, email, and password (hashed with bcrypt) and owns projects. Auth is a signed JWT stored in an httpOnly cookie, valid for 7 days.
Projects
A project is the top-level container — think "one FlagPulse project per application or service." Projects are owned by a single user (owner_id) and have a URL-safe slug derived from their name.
Creating a project also creates its first environment in the same request.
Environments
An environment belongs to a project and represents a deployment target (e.g. production, staging, local). Each environment has:
- Its own SDK key (a UUID, rotatable independently of the environment itself)
- An allowed origin URL — used to build the CORS allowlist so only that origin's SDK/SSE calls are accepted
- An icon (for the dashboard)
Rotating an SDK key invalidates the old key immediately (removed from the Redis cache) and the new key becomes valid right away.
Flags
A flag is defined once per project with a key, name, type (boolean | string | number | json), and a default_value. Creating a flag automatically creates a flag_values row for every existing environment in the project, seeded with the default value.
Flag values
A flag value is the per-environment state of a flag:
| Field | Meaning |
|---|---|
is_enabled | Whether the flag is on in this environment |
rollout_percentage | Percentage rollout (0–100) |
targeting_attribute | Attribute name to target on (e.g. userId, plan) |
targeting_value | The value of that attribute to match |
targeting_return_value | The value returned when targeting matches |
This is what lets the same flag be off in staging and on at 25% in production, independently.
Audit logs
Every mutating action — project/environment/flag creation, deletion, edits, toggles, and SDK-key rotation — writes an audit_logs row with a change_summary, optional old_value/new_value, and a domain (project, environment, or flag). Logs are queryable per project and can be cleared per project.