Full process template for citizen initiative campaign, from digital signatures' collection to PDF document rendering for legislative submission.
Table of contents
- Ready to use campaign static website (Astro, Svelte, Tailwind and DaisyUI)
- An online form with a signature pad
- Signatures counter, from both offline and online channels
- Support offline sign locations list
- Privacy policy template
- GitHub Action's Workflow file for build and deploy to GitHub Pages
- Database configuration (Firebase, and Google Sheets with Sheethuahua)
- Firebase rules for spamming protection for online submission
- Firebase emulator with mocked data for local development
- Google Sheets template for human-curated data
- Post-campaign scripts (pdf-lib and Node.js)
- Download online submission signatories' data as CSV files
- Render CSV data on the PDF template for legislative submission
The configuration file is provided, but everything can be customized via code.
Required Node.js v20 or higher with NPM package manager.
npx degit github:wevisdemo/e-initiative-template <project-name>
The template will be downloaded to the project-name
folder.
For online signature submission
- Create a new project in Firebase Console
- Set up Authentication
2.1. Enable "Email/Password" and "Anonymous" sign-in methods.
2.2. Add user and provide email/password for the admin account. Then add the same information in the local
.env.production
file (create it in the project folder if it does not exist) with theADMIN_EMAIL
andADMIN_PASSWORD
keys. 2.3. Copy the admin's User UID for the next step. - Set up Firestore Database
3.1 Enable the Firestore
3.2 Copy rules from
firestore.rules
and update admin's UID from the previous step. (Only update rules on the console,firestore.rules
is used by the local emulator) - Obtain Firebase config
3.1 Add a new web app from project settings > General > Your Apps
3.2 Copy
firebaseConfig
as a one-line JSON format and put it inPUBLIC_FIREBASE_CONFIG
of the local.env.production
file.
At the end, your .env.production
file should look like this:
PUBLIC_FIREBASE_CONFIG={"apiKey": "???", "authDomain": "???", "projectId": "???", "storageBucket": "???", "messagingSenderId": "???", "appId": "???"}
ADMIN_EMAIL=???
ADMIN_PASSWORD=???
Note: There is a .env.development
with mocked data for working with the Firebase emulator in the local development environment. You don't need to change anything there.
For human-curated data, including offline signature count and voluntary sign locations. You can skip this step if your campaign doesn't need both functions.
- Duplicate Google Sheets template. It contains 2 sheets:
- "offline-signature" sheets for recording offline signature count in each day. The total number is the summation of every row.
- "locations" is the sign location showing in the location page.
- Grant "Viewer" permission to "Anyone with the link" in Share menu
- Obtain Sheets ID from the URL
https://docs.google.com/spreadsheets/d/{sheetsID}/
and add it to thesheets.id
ine-initiative.config.mjs
- (Optional) If you allow anyone to submit a voluntary offline sign location.
4.1. Create a Google Form with fields corresponding to the columns in the
locations
sheet. 4.2. In the form response settings, link the form response to your duplicated sheets. A response sheet will be created with each question in the header. 4.2. Rename the column header to be like thelocations
sheet. Doesn't need to have the same order, but it must correspond to each question. 4.3 Remove the oldlocations
sheet and rename the form response sheet tolocations
instead.
Most of the campaign information can be configured via e-initiative.config.mjs
. Explanation can be found by hovering at the configuration keys (on JSDoc supported IDE) or the type definition file. Configuration should be updated first so that you will know what is not covered and require editing the source code.
- Website content can be directly edited through source code. The index page entry point to get started is
src/pages/index.astro
. - UI components are from either Daisy UI v3 or custom-made available in
src/components
. Svelte is mainly used, but you can install additional UI Framework integration for Astro - Color theme defined in
e-initiative.config.mjs
is available as a Tailwind class. For VSCode users, Tailwind extension is recommended for Tailwind class auto-completion. - Typography CSS global utility classes are defined in
src/styles/typography.css
and ready to be used. - Design system corresponds to the Figma
- Don't forget to review the privacy policy in
src/pages/privacy-policy.astro
and remove the "mark" tags (for highlighting) after updating the content.
To start Astro development server and Firebase emulator:
npm run dev
During the development mode, any changes to Firebase will be in the local emulator, leaving the production database untouched. Mock data will be initialized in the Firestore emulator for post-campaign script testing. The .env.development
is used.
To build a website for production:
npm run build
The static site will be generated to /dist
and we can preview the production build with
npm run preview
Note that the production build will use .env.production
and the real Firebase, not the emulator.
Since Astro uses Static Site Generation (SSG), no data from Firebase and Google Sheets will be updated after the build. So we recommended using CI/CD tools that support scheduled deployment such as GitHub Actions. Then we can periodically re-build and re-deploy in a given period. Don't forget to add all the production environment variables to the CI/CD.
The template also includes GitHub Action's workflow file .github/workflows/demo.yaml
. Please remove it before pushing to GitHub if you don't want to use it. But if you do, don't forget to add all the production environment variables as a repository secret and remove the PUBLIC_DEMO_MODE
env from the Build with Astro step.
Your PDF output template might not have the same field value/position as our given template. Before using the thousands of production records, we recommend testing with one record of mock data first.
To get mock data (Firebase emulator must be running from dev
or dev:firebase
command):
npm run download:local
Output CSV files will be generated to the /out
directory: one version with base64 signature data, and one version without it. Then start the renderer in watch mode:
npm run render:watch
The output PDF files will be re-generated to /out
directory every time any file has changed. Keep adjusting the renderer
config in e-initiative.config.mjs
until the output PDF looks pretty.
First, download the production signatories' data in CSV format (duplicated or invalid records will be filtered out):
npm run download:prod
Then, render to the PDF files:
npm run render
Both CSV and PDF files will be generated to /out
directory, replacing existing data if exists (eg. from mock data).
Citizens have the right to propose a law draft to the parliament when they can gather enough signatures (more about Thailand legislative process). The initiative leader usually follows this pattern:
-
Pre-campaign
- Create a law draft
- Design campaign content and activities
-
Campaign
- Promote the initiative
- Collect citizen signatures through offline/online channel
-
Post campaign
- Submit the draft together with all the signatures to the parliament
Our team is committed to developing all projects as Open Source and releasing data as Open Data under the Attribution-NonCommercial-ShareAlike 4.0 International license. This means the work can be used, adapted, and built upon, but it must not be used for commercial purposes or profit-making. Credit must be given to the original creators, and any derivative work must be shared under the same license as the original. WeVis Ltd. and Punch Up Ltd. are the joint licensors of this license.