Database - civiform/civiform GitHub Wiki
erDiagram
ACCOUNTS }|--o{ APPLICANTS : ""
ACCOUNTS ||--o{ TI_ORGANIZATIONS : ""
ACCOUNTS
APPLICANTS ||--|{ APPLICATIONS : ""
PROGRAMS ||--o{ APPLICATIONS : ""
APPLICATION_STATUSES ||--|{ PROGRAMS : ""
VERSIONS_PROGRAMS ||--|{ VERSIONS : ""
VERSIONS_PROGRAMS ||--|{ PROGRAMS : ""
VERSIONS_QUESTIONS ||--|{ VERSIONS : ""
VERSIONS_QUESTIONS ||--|{ QUESTIONS : ""
PROGRAMS_CATEGORIES ||--|{ CATEGORIES : ""
PROGRAMS_CATEGORIES ||--|{ PROGRAMS : ""
See this link for information on what Entity Relationship Diagrams mean.
See PostgreSQL documentation for information about column data types. varchar
is character varying
, timestamp
is timestamp without time zone
.
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
id | bigint | not null | PRIMARY KEY | |
email_address | varchar. | UNIQUE | Account email address, either from the login provider or from TI client creation | |
member_of_group_id | bigint | FOREIGN KEY | To ti_organizations, indicates account is a Trusted Intermediary | |
managed_by_group_id | bigint | FOREIGN KEY | To ti_organizations, indicates account is a client of a Trusted Intermediary | |
admin_of | varchar | Specified programs the account is an administrator of ("Program Admin") | ||
global_admin | boolean | Global system administrator ("CiviForm Admin") | ||
authority_id | varchar | UNIQUE | ID that uniquely identifies the user of the Account, from login provider | |
id_tokens | jsonb | A map of session ids to digitally-signed tokens that convey a profile in an authentication response. | ||
ti_note | varchar | A note about a client added by a Trusted Intermediary |
Indexes
-
accounts_pkey
PRIMARY KEY, btree (id) -
idx_admin_of
gin (admin_of)
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
id | bigint | not null | PRIMARY KEY | |
name | varchar | not null | Human readable name of the ApiKey. | |
create_time | timestamp | not null | Timestamp of when the the ApiKey was created. | |
update_time | timestamp | not null | Timestamp of when the the ApiKey was last modified. | |
created_by | varchar | not null | The authorityId of the account that created the ApiKey. | |
retired_time | timestamp | The time when the ApiKey was retired or empty if it is not retired. | ||
retired_by | varchar | The authority ID of the account that retired the ApiKey or empty if it is not retired. | ||
key_id | varchar | not null | UNIQUE | Identifier for the ApiKey. Paired with the password, comprises the credentials for using the ApiKey. |
salted_key_secret | varchar | not null | UNIQUE | Salted key secret (a.k.a. password) of the ApiKey. Created by signing the password with the API secret using the SHA-HMAC-256 algorithm. |
subnet | varchar | not null | An allowlist of IPv4 addresses that are permitted to authenticate with this ApiKey. Specified using CIDR notation: https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing. This attribute is a CSV, with multiple CIDR blocks separated by commas. | |
expiration | timestamp | not null | Timestamp of when the ApiKey is no longer valid. | |
call_count | bigint | not null | The number of requests that have been attempted using this API key. | |
last_call_ip_address | varchar | The client IPv4 address of the last request to successfully auth with the ApiKey. Empty if the ApiKey has never been used. | ||
grants | jsonb | not null | Permissions granted to this ApiKey by the admin. |
Indexes
-
api_keys_pkey
PRIMARY KEY, btree (id) -
api_key_ids
UNIQUE, btree (key_id)
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
id | bigint | not null | PRIMARY KEY | |
preferred_locale | varchar | Applicant selected default locale | ||
object | jsonb | not null | Map of questions to applicant answers. Used to hydrate the ApplicantData object. | |
account_id | bigint | FOREIGN KEY | To accounts. There is a 1:1 mapping of accounts to applicants. | |
when_created | timestamp | Date applicant record was created | ||
first_name | varchar | Applicant first name. Set when an applicant answers a name question marked as "Primary Applicant Info" or when a TI enters a client's name. | ||
middle_name | varchar | Applicant middle name. Set when an applicant answers a name question marked as "Primary Applicant Info" or when a TI enters a client's name. | ||
last_name | varchar | Applicant last name. Set when an applicant answers a name question marked as "Primary Applicant Info" or when a TI enters a client's name. | ||
email_address | varchar | Applicant email address. Set when an applicant answers an email question marked as "Primary Applicant Info" or when a TI enters a client's email. | ||
country_code | varchar | Country code for applicant phone number. Set when an applicant answers a phone question marked as "Primary Applicant Info" or when a TI enters a client's phone number. | ||
phone_number | varchar | Applicant phone number. Set when an applicant answers a phone question marked as "Primary Applicant Info" or when a TI enters a client's phone number. | ||
date_of_birth | date | Applicant date of birth. Set when an applicant answers a date question marked as "Primary Applicant Info" or when a TI enters a client's date of birth. |
Indexes
-
applicants_pkey
PRIMARY KEY, btree (id) -
index_date_of_birth
btree (date_of_birth) -
index_email_address
gin_trgm_ops (email_address) -
index_first_name
gin_trgm_ops (first_name) -
index_middle_name
gin_trgm_ops (middle_name) -
index_last_name
gin_trgm_ops (last_name) -
index_phone_number
gin_trgm_ops (phone_number) -
index_country_code
gin (country_code)
Sample JSON of the object
column
For more information view the backend data model page
{
"applicant": {
"Address_mailing": {
"street": "1600 Amphitheatre Pkwy",
"address line 2": "",
"city": "Mountain View",
"state": "CA",
"zip": "11111"
},
"Vehicles_in_household": [
{
"entity name": "Daily commuter",
"license_plate_number": {
"text": "ABA1056"
}
},
{
"entity name": "Pickup truck",
"license_plate_number": {
"text": "VCS5234"
}
}
]
}
}
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
id | bigint | not null | PRIMARY KEY | |
application_id | bigint | FOREIGN KEY | To applications. The application the event applies to. | |
creator_id | bigint | FOREIGN KEY | To accounts. The account that generated the event. | |
event_type | varchar | not null | While this is a varchar, it ends up being either a 0 or 1 based on this enum, which is also captured in the details. | |
details | jsonb | not null | Details about the event. | |
create_time | timestamp | not null | The time the event was created. |
This table operates on database triggers for processing application status changes. See this evolution for details on how the triggers work.
Indexes
-
application_events_pkey
PRIMARY KEY, btree (id) -
index_application_events_by_application
btree (application_id) -
index_application_events_by_creator
btree (creator_id)
Details JSON blob
{
"event_type": "STATUS_CHANGE",
"status_event": {
"email_sent": true,
"status_text": "text of the status"
}
}
{
"event_type": "NOTE_CHANGE",
"note_event": {
"note": "this is a note about the application"
}
}
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
id | bigint | not null | PRIMARY KEY | |
program_name | varchar | not null | The program name that these statuses apply to. Should be identical to the "name" column for an entry in the programs table. | |
status_definitions | jsonb | not null | Statuses defined for the program to be applied to applications. Note that this column is being migrated from the application_statuses table in order to decouple statuses from program revisions. | |
status_definitions_lifecycle_stage | varchar | not null | Whether the statuses defined in this row for the given program are the currently "active" set of statuses, or "obsolete". | |
create_time | timestamp | Date when this version of the statuses was created |
Indexes
-
application_statuses_pkey
PRIMARY KEY, btree (id)
Sample JSON of the status_definitions
column
{
"statuses": [
{
"status": "Pending",
"defaultStatus": true,
"status_localized": {
"isRequired": true,
"translations": {
"en_US": "Pending",
"es_US": "Pendiente"
}
},
"email_body_localized": {
"isRequired": true,
"translations": {
"en_US": "This application is pending",
"es_US": "Esta solicitud está pendiente"
}
}
}
]
}
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
id | bigint | not null | PRIMARY KEY | |
applicant_id | bigint | FOREIGN KEY | To applicants table | |
program_id | bigint | FOREIGN KEY | To programs table | |
object | jsonb | not null | A copy of the object from the applicants table for the applicant at the time of application submission, containing answers to all questions the applicant has answered. | |
lifecycle_stage | varchar | Status of the application (draft or active) | ||
submit_time | timestamp | Date application record was submitted | ||
submitter_email | varchar | Email of the TI who submitted the application. This is null if the applicant submitted themselves. | ||
create_time | timestamp | Date application record was created | ||
preferred_locale | varchar | Applicant selected default locale | ||
latest_status | varchar | The status currently applied to the application. This column is updated by database triggers from the application_events table. | ||
latest_note | varchar | The note currently added to the application. This column is updated using database update statements at the ApplicationEventRepository. | ||
submission_duration | interval | Calculated as (submit_time - create_time). See this | ||
is_admin | boolean | Indicates if the application belongs to an admin, used as part of the program preview features. See this for more details. |
Indexes
-
applications_pkey
PRIMARY KEY, btree (id) -
index_applications_by_submit_time
btree (submit_time) -
index_applications_by_submit_time_and_id
btree (submit_time DESC, id DESC)
Sample JSON of the object
column
For more information view the backend data model page
{
"applicant": {
"Address_mailing": {
"street": "1600 Amphitheatre Pkwy",
"address line 2": "",
"city": "Mountain View",
"state": "CA",
"zip": "11111"
},
"Vehicles_in_household": [
{
"entity name": "Daily commuter",
"license_plate_number": {
"text": "ABA1056"
}
},
{
"entity name": "Pickup truck",
"license_plate_number": {
"text": "VCS5234"
}
}
]
}
}
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
id | bigint | not null | PRIMARY KEY | |
settings | jsonb | not null | JSON blob with ADMIN_WRITEABLE settings | |
create_time | timestamp | not null | The date this version of the settings was created | |
created_by | varchar | not null | What created the settings. Currently always "system", or "test" for unit tests. |
Indexes
-
civiform_settings_pkey
PRIMARY KEY, btree (id) -
civiform_settings_create_time
UNIQUE, btree (create_time)
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
id | bigint | not null | PRIMARY KEY | |
name | varchar | Name of the file as stored in the file bucket. | ||
original_file_name | varchar | Used primarily for Azure since files are stored as UUIDs. See this | ||
acls | jsonb | Set which admins for a particular program have access to this file. See this |
Indexes
-
files_pkey
PRIMARY KEY, btree (id) -
index_file_names
UNIQUE, btree (name)
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
id | bigint | not null | PRIMARY KEY | |
job_name | varchar | not null | Name of the job as defined here | |
execution_time | timestamp | not null | The next scheduled time for the job to run. | |
success_time | timestamp | The time when the job run succeeded. | ||
create_time | timestamp | not null | When this scheduled job entry was created. | |
remaining_attempts | smallint | not null | How many more times we will try rerunning a failed job before giving up. | |
error_message | varchar | Error message that was logged when the job failed. |
Indexes
-
persisted_durable_jobs_pkey
PRIMARY KEY, btree (id) -
index_persisted_durable_jobs_by_execution_time
btree (execution_time) -
index_persisted_durable_jobs_by_success_time
btree (success_time)
Internal tables used by the Play Framework for applying and recording database evolutions. Should not be modified by application code.
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
id | bigint | not null | PRIMARY KEY | |
name | varchar | Name of the program, unique per program, but not in the database. Different versions of the same program are linked by their immutable name. | ||
description | varchar | Private note about the program viewable only to admins. | ||
block_definitions | jsonb | not null | Screens are defined here along with linking questions to screens | |
slug | varchar | Used when creating a permalink to the new application of a program. A URL-safe version of the name. | ||
localized_name | jsonb | Translated versions of the program name | ||
localized_description | jsonb | Translated versions of the program description | ||
external_link | varchar | URL to a resource outside of the application | ||
display_mode | varchar | not null | Determines the visibility of the program to different users. See the DisplayMode enum | |
create_time | timestamp | Date this program revision was created | ||
last_modified_time | timestamp | Last time this program was modified (when in draft state) | ||
program_type | varchar | Denotes if it is a standard program or a common intake form. See ProgramType | ||
eligibility_is_gating | boolean | If true, eligibility conditions should gate application submission for this program. If false, ineligible applications will still be allowed to be submitted. | ||
localized_confirmation_message | jsonb | Used to display a custom message on the application confirmation screen after an applicant submits an application | ||
acls | jsonb | In the Program Details screen, when the program visibility is set to "Visible to selected trusted intermediaries only", this contains the list of IDs of the TI organizations allowed to view this program. | ||
localized_summary_image_description | jsonb | A localized description of the summary image used for the program, used as alt text on the image. | ||
summary_image_file_key | varchar | A key used to fetch the program's summary image from cloud storage | ||
localized_short_description | jsonb | not null | Translated versions of a short program description (< 100 characters) | |
application_steps | jsonb | not null | Overall steps an applicant should be aware of when applying to a program |
Indexes
-
programs_pkey
PRIMARY KEY, btree (id)
Sample JSON of the block_definitions
column
[
{
"id": 1,
"name": "Screen 1",
"repeaterId": null,
"description": "Screen 1 Description",
"hidePredicate": null,
"optionalPredicate": null,
"questionDefinitions": [
{
"id": 1,
"optional": false,
"addressCorrectionEnabled": false
},
{
"id": 2,
"optional": false,
"addressCorrectionEnabled": false
}
]
},
{
"id": 2,
"name": "Screen 2",
"repeaterId": null,
"description": "Screen 2 Description",
"hidePredicate": null,
"optionalPredicate": null,
"questionDefinitions": [
{
"id": 3,
"optional": false
}
]
},
{
"id": 3,
"name": "Screen 3",
"repeaterId": null,
"description": "Screen 3 Description",
"hidePredicate": {
"action": "SHOW_BLOCK",
"rootNode": {
"node": {
"type": "leaf",
"value": {
"type": "LIST_OF_STRINGS",
"value": "[\"0\"]"
},
"scalar": "SELECTION",
"operator": "IN",
"questionId": 4
}
}
},
"optionalPredicate": null,
"questionDefinitions": [
{
"id": 5,
"optional": false
}
]
},
{
"id": 4,
"name": "Screen 4",
"repeaterId": 3,
"description": "Screen 4 Description",
"hidePredicate": null,
"optionalPredicate": null,
"questionDefinitions": [
{
"id": 6,
"optional": false
},
{
"id": 7,
"optional": false
}
]
}
]
Sample JSON of the localized_name
, localized_description
, localized_confirmation_message
, and localized_summary_image_description
columns
{
"isRequired": true,
"translations": {
"en_US": "English Text",
"es_US": "Spanish Text"
}
}
Sample JSON of the acls
column
{
"tiProgramViewAcls": [1,2]
}
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
id | bigint | not null | PRIMARY KEY | |
name | varchar | Immutable name of the question | ||
description | varchar | Description of the question | ||
question_type | varchar | Type of question. Corresponds to the QuestionType enum | ||
validation_predicates | jsonb | Configuration for question validation requirements | ||
enumerator_id | bigint | The question id of an ENUMERATOR question_type. It signifies that this questions is part of the enumerator and repeats for each entry. | ||
question_options | jsonb | The list of valid options for questions that have pre-defined answers (e.g. CHECKBOX, DROPDOWN) | ||
question_text | jsonb | Text of the question presented to the applicant in their preferred language | ||
question_help_text | jsonb | Help text of the question presented to the applicant in their preferred language | ||
enumerator_entity_type | jsonb | Text of the thing we are enumerating presented to the applicant in their preferred language | ||
question_tags | varchar[] | An array of QuestionTags, denoting things such as whether the question answer should be marked as demographic information, or if the question is a Primary Applicant Info question. | ||
create_time | timestamp | Date this revision of the question was created |
For information on versioning questions and programs see the data versioning model page.
Indexes
-
questions_pkey
PRIMARY KEY, btree (id) -
idx_question_tags
gin (question_tags) -
questions_by_name
btree (name)
Sample JSON of the validation_predicates
column
Question Type: ADDRESS
{
"type": "address",
"disallowPoBox": false
}
Question Type: CHECKBOX
, DROPDOWN
, & RADIO_BUTTON
{
"type": "multioption",
"maxChoicesAllowed": 2,
"minChoicesRequired": 1
}
Question Type: ID
& TEXT
{
"type": "text",
"maxLength": 9,
"minLength": 5
}
Question Type: NUMBER
{
"type": "number",
"max": 200,
"min": 1
}
Sample JSON of the question_options
column
[
{
"id": 0,
"displayOrder": 0,
"localizedOptionText": {
"isRequired": true,
"translations": {
"en_US": "English text",
"es_US": "Spanish text"
}
}
}
]
Sample JSON of the question_text
, question_help_text
, and enumerator_entity_type
columns
{
"isRequired": true,
"translations": {
"en_US": "English text",
"es_US": "Spanish text"
}
}
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
id | bigint | not null | PRIMARY KEY | |
name | varchar | not null | Name of the organization | |
description | varchar | Description of the organization |
Indexes
-
ti_organizations_pkey
PRIMARY KEY, btree (id)
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
id | bigint | not null | PRIMARY KEY | |
lifecycle_stage | varchar | not null | Defines which versions are active, draft, or obsolete. Corresponds to the LifecycleStage enum | |
submit_time | timestamp | Date when last saved | ||
tombstoned_question_names | varchar[] | When a question is marked as "archived" in a draft, it shows up in this | ||
tombstoned_program_names | varchar[] | In the future, if we support archiving programs, this will be used. Currently unused. |
For information on versioning questions
and programs
see the data versioning model page.
Indexes
-
versions_pkey
PRIMARY KEY, btree (id)
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
programs_id | bigint | not null | !!! No actual foreign key reference in db. Foreign key to programs table |
|
versions_id | bigint | not null | !!! No actual foreign key reference in db. Foreign key to versions table |
Indexes
-
versions_programs_pkey
PRIMARY KEY, btree (id)
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
questions_id | bigint | not null | !!! No actual foreign key reference in db. Foreign key to questions table |
|
versions_id | bigint | not null | !!! No actual foreign key reference in db. Foreign key to versions table |
Indexes
-
versions_questions_pkey
PRIMARY KEY, btree (id)
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
id | bigint | not null | PRIMARY KEY | |
localized_name | jsonb | not null | Translations of the category name | |
create_time | timestamp | not null | Timestamp of when the the category was created. | |
last_modified_time | timestamp | Timestamp of when the the category was last modified. | ||
lifecycle_stage | varchar | not null | Defines which categories are active or obsolete. |
Indexes
-
categories_pkey
PRIMARY KEY, btree (id)
Sample JSON of the localized_name
column
{
"isRequired": true,
"translations": {
"am": "ኢኮኖሚያዊ",
"ko": "경제",
"lo": "ເສດຖະກິດ",
"so": "Dhaqaale",
"tl": "Pang-ekonomiya",
"vi": "Kinh tế",
"en_US": "Economic",
"es_US": "Economía",
"zh_TW": "經濟"
}
}
Column | Type | Nullable | Properties | Description |
---|---|---|---|---|
programs_id | bigint | not null | Foreign key to the programs table. | |
categories_id | bigint | not null | Foreign key to the categories table. |
Indexes
-
programs_categories_pkey
PRIMARY KEY, btree (programs_id, categories_id)
Be very careful when writing a new database evolution! Once it goes out in a release, if it needs fixes, it's pretty hard to untangle. Evolutions should generally be considered immutable, and should only be changed in the most dire of circumstances, such as it being likely to break new deployments in the future. We should avoid one-way destructive evolutions, and always have a way of reversing the destructive actions in the downs.
Evolutions should really just be for changing the structure of the database and not the data itself. When updating data, a Durable Job is preferred.
Ensure creation/removal of resources is guarded by IF NOT EXISTS
and IF EXISTS
. This allows manual fixes to happen without preventing the evolution from being applied.
When possible, do not go back and change a previously released evolution. Try to create a new evolution that fixes the problem. If this is not possible, an existing evolution can be changed, but be aware that the Downs
section will be run before the new version of the evolution Ups
is applied. If this involves destructively removing data, make sure this isn't going to remove critical user data. Also, most production environments will not allow destructive downs by default, and will require turning on the DATABASE_APPLY_DESTRUCTIVE_CHANGES
flag temporarily in order to apply the new revision of the evolution.
Durable jobs allow updates to data to occur either on startup or as a recurring background job, but we expect data migrations to be done through a startup job. For any data changes via durable jobs, we should thoroughly test the change and include a rollback plan (which would likely involve adding a rollback job to the PR - see example here). We also shouldn't do a migration and delete data in one go to avoid data loss.
These can be executed locally through bin/dev-psql
Shows question revisions and their lifecycle. The distinct
usages will hide all other obsolete revisions of which there can be many.
SELECT distinct questions.id AS question_id, questions.name, versions.lifecycle_stage
FROM questions
LEFT JOIN versions_questions ON (questions.id = versions_questions.questions_id)
LEFT JOIN versions ON versions.id = versions_questions.versions_id
ORDER BY questions.name, questions.id desc;
Sample output:
question_id | name | lifecycle_stage
-------------+---------------------+-----------------
2 | Income Verification | draft
1 | Income Verification | active
1 | Income Verification | obsolete
5 | test enum | draft
3 | test enum | active
3 | test enum | obsolete
Similar to above but excludes obsolete as there can be many over time.
SELECT DISTINCT programs.id, programs.name, programs.create_time, versions.lifecycle_stage
FROM programs
LEFT JOIN versions_programs ON (programs.id = versions_programs.programs_id)
LEFT JOIN versions on versions.id = versions_programs.versions_id
WHERE lifecycle_stage != 'obsolete'
ORDER BY name, id desc;
Sample output:
id | name | create_time | lifecycle_stage
----+--------------+-------------------------+-----------------
7 | test program | 2022-04-26 14:25:27.125 | active
8 | v37 program | 2022-04-26 14:38:35.596 | draft
6 | v37 program | 2022-04-25 15:18:19.592 | active
SELECT
q.name,
q.description,
q.question_type,
q.question_text->'translations'->>'en_US' AS question_text,
q.question_help_text->'translations'->>'en_US' AS question_help_text,
q.enumerator_entity_type->'translations'->>'en_US' AS enumerator_entity_type,
(
SELECT STRING_AGG(qo->'localizedOptionText'->'translations'->>'en_US', '; ')
FROM jsonb_array_elements(q.question_options) qo
) AS question_options,
q.last_modified_time
FROM versions v
LEFT JOIN versions_questions vq ON v.id = vq.versions_id
LEFT JOIN questions q ON vq.questions_id = q.id
WHERE v.lifecycle_stage = 'active';
This includes some fields that give information about the question, like the name, description and type, and the other fields are the english text for translation. Repeated fields will be in one cell and separated by a semi-colon. Note: this outputs all the text, so it shouldn't be used to find only text that hasn't been translated.
SELECT
p.name,
p.description,
p.display_mode,
p.last_modified_time,
(
SELECT STRING_AGG(qo->'localizedName'->'translations'->>'en_US', '; ')
FROM jsonb_array_elements(p.block_definitions) qo
) AS block_names,
(
SELECT STRING_AGG(qo->'localizedDescription'->'translations'->>'en_US', '; ')
FROM jsonb_array_elements(p.block_definitions) qo
) AS block_descriptions,
p.localized_name->'translations'->>'en_US' AS localized_name,
p.localized_description->'translations'->>'en_US' AS localized_description,
p.localized_summary_image_description->'translations'->>'en_US' AS localized_summary_image_description
FROM versions v
LEFT JOIN versions_programs vp ON v.id = vp.versions_id
LEFT JOIN programs p ON vp.programs_id = p.id
WHERE v.lifecycle_stage = 'active';
This includes some fields that give information about the program, like the name, description, display mode and last modified time, and the other fields are the english text for translation. Repeated fields will be in one cell and separated by a semi-colon. Note: this outputs all the text, so it shouldn't be used to find only text that hasn't been translated.
Go to the cluster page.
Go to the service page.
Click the Task Definition.
Click container definition.
Under environment variabels...
Add this (DATABASE_APPLY_DESTRUCTIVE_CHANGES
: `true):
Back to the cluster page, click update service:
And configure like so, selecting your new task definition and ticking "force new deployment":
We use pgAdmin as a tool to visualize the database and view database logs.
When working locally, run bin/dev-pgadmin
and then go to "http://localhost:8012/browser/". The dev DB password is "example".
If you get an error when running bin/dev-pgadmin
that /tmp/servers.json: Is a directory
, run sudo rmdir /tmp/servers.json
Note: if you're changing any program or question data through pgadmin or psql, you'll have to clear the cache in DevTools to see the change reflected.