update requirements,

This commit is contained in:
louiscklaw
2025-05-09 14:14:00 +08:00
parent fe1740d76f
commit 299567dd7c
35 changed files with 5054 additions and 694 deletions

View File

@@ -24,5 +24,4 @@ mindmap
Tools
Pen and paper
Mermaid
```

View File

@@ -1,9 +1,27 @@
---
tags: mobile, lesson
tags: time
---
# lesson page documentation
# time tracking
it should have a lesson page
T.B.A.
![alt text](image.png)
```mermaid
gantt
title A Gantt Diagram
dateFormat YYYY-MM-DD
section Section
A task :a1, 2014-01-01, 30d
Another task :after a1, 20d
section Another
Task in Another :2014-01-12, 12d
another task :24d
```
---
## TODOs of the project
- [cms TODO](../../../002_source/cms/TODO.md)
- [ionic TODO](../../../002_source/ionic_mobile/TODO.md)
- [pocketbase TODO](../../../002_source/pocketbase/TODO.md)

View File

@@ -0,0 +1,20 @@
# task
update `dbml` from `schema.json`, for collection `billingAddress`
## Background information
1. please ignore `presentable` properties from `schema.json`, this is for pocketbase internal usage
1. please ignore collections with `_` as its first character, this is for pocketbase internal usage
1. just return the collection with `billingAddress` is ok, please ignore other collections
## steps
1. read file `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/002_source/cms/src/db/schema.json`. this is the export from `pocketbase`.
1. read file `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/001_documentation/Requirements/REQ0006/schema.dbml`. this is file written in dbml format.
1. currently the collection in `schama.json` is mapped to table in `schema.dbml`
1. compare the `schema.json` and `schema.dbml`, remember the differences
1. you may found some comment already exist in `schema.dbml`, please keep them
1. while keeping `schema.json` content unchanged. write file to `/home/logic/_wsl_workspace/001_github_ws/lettersoup-online-ws/lettersoup-online/project/001_documentation/Requirements/REQ0006/schema_ai_draft.dbml` content based on `schema.json`.
thanks.

View File

@@ -1,20 +0,0 @@
# LessonCategories / LessonCategory
Hi, using information from
- @schema.dbml for schemas, fields and table names,
- @listHelloworld.ts for skeleton for ts script
- @listVocabularies.ts, @listUserMetas.ts, @listQuizListening.ts, @listQuisMatching.ts, @listQuizConnectivesCategories for reference
extend @listLessonCategories.ts to cover `LessonCategories`,
draft `ts` code
- `CRUD`
- `getFulllistLessonCategories,`
- `getListByFilterLessonCategories,`
- `getFirstListItemLessonCategories,`
- `getOneLessonCategory,`
- `getListLessonCategoryById`
thanks

View File

@@ -1,20 +0,0 @@
# LessonTypes / LessonType
Hi, using information from
- @schema.dbml for schemas, fields and table names,
- @listHelloworld.ts for skeleton for ts script
- @listVocabularies.ts, @listUserMetas.ts, @listQuizListening.ts, @listQuisMatching.ts, @listQuizConnectivesCategories for reference
extend @listLessonTypes.ts to cover `LessonTypes`,
draft `ts` code
- `CRUD`
- `getFulllistLessonTypes,`
- `getListByFilterLessonTypes,`
- `getFirstListItemLessonTypes,`
- `getOneLessonType,`
- `getListLessonTypeById`
thanks

View File

@@ -1,20 +0,0 @@
# QuizCategories / QuizCategory
Hi, using information from
- @schema.dbml for schemas, fields and table names,
- @listHelloworld.ts for skeleton for ts script
- @listVocabularies.ts, @listUserMetas.ts, @listQuizListening.ts, @listQuisMatching.ts, @listQuizConnectivesCategories for reference
extend @listQuizCategories.ts to cover `QuizCategories`,
draft `ts` code
- `CRUD`
- `getFulllistQuizCategories,`
- `getListByFilterQuizCategories,`
- `getFirstListItemQuizCategories,`
- `getOneQuizCategory,`
- `getListQuizCategoryById`
thanks

View File

@@ -1,20 +0,0 @@
# QuizConnectives / QuizConnective
Hi, using information from
- @schema.dbml for schemas, fields and table names,
- @listHelloworld.ts for skeleton for ts script
- @listVocabularies.ts, @listUserMetas.ts, @listQuizListening.ts, @listQuisMatching.ts, @listQuizConnectivesCategories for reference
extend @listQuizConnectives.ts to cover `QuizConnectives`,
draft `ts` code
- `CRUD`
- `getFulllistQuizConnectives,`
- `getListByFilterQuizConnectives,`
- `getFirstListItemQuizConnectives,`
- `getOneQuizConnective,`
- `getListQuizConnectiveById`
thanks

View File

@@ -1,20 +0,0 @@
# QuizConnectivesCategories / QuizConnectivesCategory
Hi, using information from
- @schema.dbml for schemas, fields and table names,
- @listHelloworld.ts for skeleton for ts script
- @listVocabularies.ts, @listUserMetas.ts, @listQuizListening.ts, @listQuisMatching.ts, @listQuizConnectivesCategories for reference
extend @listQuizConnectivesCategories.ts to cover `QuizConnectivesCategories`,
draft `ts` code
- `CRUD`
- `getFulllistQuizConnectivesCategories,`
- `getListByFilterQuizConnectivesCategories,`
- `getFirstListItemQuizConnectivesCategories,`
- `getOneQuizConnectivesCategory,`
- `getListQuizConnectivesCategoryById`
thanks

View File

@@ -1,20 +0,0 @@
# QuizListenings / QuizListening
Hi, using information from
- @schema.dbml for schemas, fields and table names,
- @listHelloworld.ts for skeleton for ts script
- @listVocabularies.ts, @listUserMetas.ts, @listQuizListening.ts, @listQuisMatching.ts, @listQuizConnectivesCategories for reference
extend @listQuizListenings.ts to cover `QuizListenings`,
draft `ts` code
- `CRUD`
- `getFulllistQuizListenings,`
- `getListByFilterQuizListenings,`
- `getFirstListItemQuizListenings,`
- `getOneQuizListening,`
- `getListQuizListeningById`
thanks

View File

@@ -1,20 +0,0 @@
# QuizMatchings / QuizMatching
Hi, using information from
- @schema.dbml for schemas, fields and table names,
- @listHelloworld.ts for skeleton for ts script
- @listVocabularies.ts, @listUserMetas.ts, @listQuizListening.ts, @listQuisMatching.ts, @listQuizConnectivesCategories for reference
extend @listQuizMatchings.ts to cover `QuizMatchings`,
draft `ts` code
- `CRUD`
- `getFulllistQuizMatchings,`
- `getListByFilterQuizMatchings,`
- `getFirstListItemQuizMatchings,`
- `getOneQuizMatching,`
- `getListQuizMatchingById`
thanks

View File

@@ -1,20 +0,0 @@
# UserMetas / UserMeta
Hi, using information from
- @schema.dbml for schemas, fields and table names,
- @listHelloworld.ts for skeleton for ts script
- @listVocabularies.ts, @listUserMetas.ts, @listQuizListening.ts, @listQuisMatching.ts, @listQuizConnectivesCategories for reference
extend @listUserMetas.ts to cover `UserMetas`,
draft `ts` code
- `CRUD`
- `getFulllistUserMetas,`
- `getListByFilterUserMetas,`
- `getFirstListItemUserMetas,`
- `getOneUserMeta,`
- `getListUserMetaById`
thanks

View File

@@ -1,20 +0,0 @@
# Users / User
Hi, using information from
- @schema.dbml for schemas, fields and table names,
- @listHelloworld.ts for skeleton for ts script
- @listVocabularies.ts, @listUserMetas.ts, @listQuizListening.ts, @listQuisMatching.ts, @listQuizConnectivesCategories for reference
extend @listUsers.ts to cover `Users`,
draft `ts` code
- `CRUD`
- `getFulllistUsers,`
- `getListByFilterUsers,`
- `getFirstListItemUsers,`
- `getOneUser,`
- `getListUserById`
thanks

View File

@@ -1,20 +0,0 @@
# Vocabularies / Vocabulary
Hi, using information from
- @schema.dbml for schemas, fields and table names,
- @listHelloworld.ts for skeleton for ts script
- @listVocabularies.ts, @listUserMetas.ts, @listQuizListening.ts, @listQuisMatching.ts, @listQuizConnectivesCategories for reference
extend @listVocabularies.ts to cover `Vocabularies`,
draft `ts` code
- `CRUD`
- `getFulllistVocabularies,`
- `getListByFilterVocabularies,`
- `getFirstListItemVocabularies,`
- `getOneVocabulary,`
- `getListVocabularyById`
thanks

View File

@@ -0,0 +1,6 @@
# GUIDELINES
- `schema.dbml` means DB schema in `dbml` format
- `schema.json` contains the exported DB schema from pocketbase
- the `Collection ID: xxx` in `dbml` file contains the collection `id` mapping from `schema.json`
- the `presentable` field from `json` file should be ignored.

View File

@@ -0,0 +1,86 @@
//
// # REQ0015:
// ## PURPOSE:
//
// This is a script to convert `schema.json` exported from pocketbase to dbml formatted file `schema.dbml`
//
//
const fs = require("fs");
const path = require("path");
// Load schema.json
const schemaPath = path.join(process.cwd(), "schema.json");
const schema = JSON.parse(fs.readFileSync(schemaPath, "utf8"));
// Type mapping from PocketBase to DBML/SQL
const typeMapping = {
text: "text",
number: "integer",
bool: "boolean",
email: "text",
url: "varchar",
date: "datetime",
select: "varchar",
json: "text",
file: "file",
password: "varchar",
relation: "integer", // Assuming relations are stored as integer IDs
autodate: "datetime",
};
function convertToDBML(schema) {
let dbml = "";
dbml = "// Generated at: " + new Date().toISOString();
dbml = dbml + "\n\n\n";
let collectionIdToTableMapping = {};
for (const [idx, tableDef] of Object.entries(schema)) {
collectionIdToTableMapping[tableDef.id] = tableDef.name;
}
for (const [idx, tableDef] of Object.entries(schema)) {
console.log({ idx });
dbml += `// \n`;
dbml += `// collection id: ${tableDef.id} \n`;
dbml += `// collection name: ${tableDef.name} \n`;
dbml += `// collection type: ${tableDef.type} \n`;
dbml += `Table ${tableDef.name} {\n`;
for (const field of tableDef.fields) {
// Get field type
let fieldType = typeMapping[field.type] || "text";
// Handle special cases
if (field.type === "number" && field.options?.max === 1) {
fieldType = "boolean";
}
// Build field definition
let line = ` ${field.name} ${fieldType}`;
// Add constraints
const constraints = [];
if (field.name === "id" || field.primary) constraints.push("pk");
if (field.required) constraints.push("not null");
if (constraints.length > 0) line += ` [${constraints.join(", ")}]`;
if (field.collectionId) {
line += ` [ref: > ${
collectionIdToTableMapping[field.collectionId]
}.id] // ${field.id}`;
}
dbml += `${line}\n`;
console.log({ line });
}
dbml += "}\n\n";
}
return dbml;
}
// Convert and save
const dbmlOutput = convertToDBML(schema);
fs.writeFileSync("schema.dbml", dbmlOutput);
console.log("DBML file generated successfully!");

View File

@@ -0,0 +1,31 @@
import { faker } from "@faker-js/faker";
const getId = (id) => id.padStart(15, "0");
const row_array = Array.from({ length: 10 }, (_, i) => [
getId(String(i + 1)),
faker.person.firstName(),
"",
faker.internet.email(),
faker.phone.number(),
faker.company.name(),
{
country: faker.location.country(),
state: faker.location.state(),
city: faker.location.city(),
zipCode: faker.location.zipCode(),
line1: faker.location.streetAddress(),
line2: faker.location.secondaryAddress(),
},
Math.floor(Math.random() * (100 - 0 + 1)) + 0,
faker.location.timeZone(),
["en", "de", "es", "fr", "ja", "ko", "zh-CN"].sort(
() => Math.random() - 0.5
)[0],
faker.finance.currencyCode(),
]);
import fs from "fs";
const filePath = "output.json";
fs.writeFileSync(filePath, JSON.stringify(row_array, null, 2));
console.log(`Wrote ${row_array.length} records to ${filePath}`);

View File

@@ -0,0 +1,202 @@
[
[
"000000000000001",
"May",
"",
"June_Wintheiser33@hotmail.com",
"281-378-5900 x822",
"Green, Rempel and Hoeger",
{
"country": "Central African Republic",
"state": "Arizona",
"city": "Winfieldburgh",
"zipCode": "92017-8004",
"line1": "1838 Willa Freeway",
"line2": "Suite 307"
},
98,
"Asia/Urumqi",
"de",
"MUR"
],
[
"000000000000002",
"Marilyne",
"",
"Carol_Blick@yahoo.com",
"(893) 919-2445 x193",
"White - Hessel",
{
"country": "Iraq",
"state": "Nevada",
"city": "Casa Grande",
"zipCode": "83831-3843",
"line1": "6984 Alberto Radial",
"line2": "Suite 154"
},
49,
"Africa/Tunis",
"zh-CN",
"CHF"
],
[
"000000000000003",
"Jacklyn",
"",
"Tamara_Lynch11@yahoo.com",
"597-593-0144 x168",
"Rolfson LLC",
{
"country": "Grenada",
"state": "Georgia",
"city": "New Brodyfort",
"zipCode": "18887-7075",
"line1": "493 Pfannerstill Meadow",
"line2": "Apt. 358"
},
44,
"Asia/Manila",
"zh-CN",
"CDF"
],
[
"000000000000004",
"Alana",
"",
"Ahmed_Willms@hotmail.com",
"401.212.0386 x31125",
"Friesen, Langworth and Thompson",
{
"country": "Australia",
"state": "North Carolina",
"city": "Fort Jerrell",
"zipCode": "14211",
"line1": "1763 West Street",
"line2": "Suite 699"
},
34,
"America/Boa_Vista",
"ja",
"KES"
],
[
"000000000000005",
"Rocky",
"",
"Angela_Kuhic@gmail.com",
"653.964.0412",
"Hayes - Morar",
{
"country": "Reunion",
"state": "New York",
"city": "Kayton",
"zipCode": "82048-0645",
"line1": "636 Angel Junction",
"line2": "Apt. 361"
},
70,
"America/Grand_Turk",
"fr",
"PGK"
],
[
"000000000000006",
"Carmela",
"",
"Larry94@hotmail.com",
"1-508-980-1889 x134",
"Goodwin - Brown",
{
"country": "Heard Island and McDonald Islands",
"state": "Wisconsin",
"city": "Jalenbury",
"zipCode": "75732-7013",
"line1": "669 Sven Trail",
"line2": "Suite 409"
},
48,
"Asia/Karachi",
"fr",
"AMD"
],
[
"000000000000007",
"Lucious",
"",
"Lera67@yahoo.com",
"(684) 748-3653 x8745",
"Harvey - Kilback",
{
"country": "Israel",
"state": "Maryland",
"city": "East Allenmouth",
"zipCode": "21779",
"line1": "6070 W Grand Avenue",
"line2": "Suite 448"
},
83,
"America/St_Barthelemy",
"en",
"SBD"
],
[
"000000000000008",
"Anika",
"",
"Shane.Moore@gmail.com",
"(996) 909-3575 x614",
"Donnelly, Larson and Stamm",
{
"country": "Canada",
"state": "Michigan",
"city": "Lafayette",
"zipCode": "90430-8775",
"line1": "430 Orland Place",
"line2": "Suite 891"
},
64,
"America/Toronto",
"fr",
"PKR"
],
[
"000000000000009",
"Otto",
"",
"Emery_Wisozk@yahoo.com",
"1-602-251-7035 x9461",
"Kreiger - Boehm",
{
"country": "South Georgia and the South Sandwich Islands",
"state": "Colorado",
"city": "Lake Isaias",
"zipCode": "26025-5909",
"line1": "143 Kautzer Unions",
"line2": "Apt. 752"
},
98,
"Africa/Ndjamena",
"fr",
"JOD"
],
[
"000000000000010",
"Cortez",
"",
"Jameson13@hotmail.com",
"1-660-472-1494",
"Parisian LLC",
{
"country": "Mali",
"state": "Illinois",
"city": "Stammburgh",
"zipCode": "92318",
"line1": "7669 Jude Drive",
"line2": "Apt. 594"
},
59,
"Africa/Lubumbashi",
"en",
"VND"
]
]

View File

@@ -0,0 +1,33 @@
{
"name": "gen_customer",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "gen_customer",
"version": "1.0.0",
"license": "ISC",
"devDependencies": {
"@faker-js/faker": "^9.7.0"
}
},
"node_modules/@faker-js/faker": {
"version": "9.7.0",
"resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.7.0.tgz",
"integrity": "sha512-aozo5vqjCmDoXLNUJarFZx2IN/GgGaogY4TMJ6so/WLZOWpSV7fvj2dmrV6sEAnUm1O7aCrhTibjpzeDFgNqbg==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/fakerjs"
}
],
"license": "MIT",
"engines": {
"node": ">=18.0.0",
"npm": ">=9.0.0"
}
}
}
}

View File

@@ -0,0 +1,15 @@
{
"name": "gen_customer",
"version": "1.0.0",
"main": "gen_customer.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"@faker-js/faker": "^9.7.0"
}
}

View File

@@ -0,0 +1,23 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.:
devDependencies:
'@faker-js/faker':
specifier: ^9.7.0
version: 9.7.0
packages:
'@faker-js/faker@9.7.0':
resolution: {integrity: sha512-aozo5vqjCmDoXLNUJarFZx2IN/GgGaogY4TMJ6so/WLZOWpSV7fvj2dmrV6sEAnUm1O7aCrhTibjpzeDFgNqbg==}
engines: {node: '>=18.0.0', npm: '>=9.0.0'}
snapshots:
'@faker-js/faker@9.7.0': {}

View File

@@ -1,266 +1,465 @@
// Users table with auth fields
Table Users {
// system field
id text [pk]
tokenKey text [not null]
created datetime [default: `now()`]
updated datetime
password text [not null]
// Generated at: 2025-05-08T05:00:49.862Z
// value field
//
// collection id: pbc_3142635823
// collection name: _superusers
// collection type: auth
Table _superusers {
id text [pk, not null]
password varchar [not null]
tokenKey text [not null]
email text [not null]
emailVisibility boolean
verified boolean
created datetime
updated datetime
}
//
// collection id: _pb_users_auth_
// collection name: users
// collection type: auth
Table users {
id text [pk, not null]
password varchar [not null]
tokenKey text [not null]
email text [not null]
emailVisibility boolean
verified boolean
name text
avatar file
created datetime
updated datetime
visible text
}
// LessonTypes stores different types of lessons
// lesson_types, lesson_type
Table LessonTypes {
// system field
id text [pk] // changed from int to text
created datetime [default: `now()`] // timestamp when the lesson type was created
updated datetime // timestamp when the lesson type was last updated
// value field
name text // changed from varchar to text
type text // changed from varchar to text
//
// collection id: pbc_1430376151
// collection name: Categories
// collection type: base
Table Categories {
id text [pk, not null]
cat_name text
cat_image_url text
cat_image file
pos integer
lesson_id integer [ref: > LessonsTypes.id] // relation3455582614
remarks text
visible text
created datetime
updated datetime
}
//
// collection id: pbc_108570809
// collection name: Customers
// collection type: base
Table Customers {
id text [pk, not null]
name text
email text
phone text
quota integer
status text
avatar_file file
user_id integer [ref: > users.id] // relation2809058197
billingAddress text
timezone text
language text
currency text
created datetime
updated datetime
}
//
// collection id: pbc_1196309394
// collection name: LessonsCategories
// collection type: base
Table LessonsCategories {
id text [pk, not null]
cat_name text
cat_image_url text
cat_image file
pos integer
lesson_id integer [ref: > LessonsTypes.id] // relation3455582614
description text
remarks text
visible text
created datetime
updated datetime
}
//
// collection id: pbc_2328411368
// collection name: LessonsTypes
// collection type: base
Table LessonsTypes {
id text [pk, not null]
name text
type text
pos integer
visible text
field date
}
// LessonCategories stores categories of lessons
// lesson_categories, lesson_category
Table LessonCategories {
// system field
id text [pk] // changed from int to text
created datetime [default: `now()`] // timestamp when the category was created
updated datetime // timestamp when the category was last updated
// value field
cat_name text // changed from varchar to text
cat_image_url text // new field
cat_image file // changed from varchar to file
pos integer
lesson_id integer [ref: > LessonTypes.id] // foreign key referencing LessonTypes.id
description text // new field
remarks text // changed from varchar to text
visible text // new field
}
Table Helloworlds {
// system field
id text [pk] // changed from int to text
created datetime [default: `now()`] // record create time
updated datetime // record update time
hello text // new field
}
Table UserMetas {
// system field
id text [pk] // changed from int to text
created datetime [default: `now()`]
created datetime
updated datetime
// value field
helloworld text // changed from varchar to text
meta json // new field
user_id text [ref: > Users.id] // changed type and reference
state text // new field
avatar file // changed from blob to file
role text // new field
field datetime
}
Table QuizCategories {
// system field
id text [pk] // changed from int to text
created datetime [default: `now()`]
//
// collection id: pbc_977978967
// collection name: Notifications
// collection type: base
Table Notifications {
id text [pk, not null]
read boolean
type text
author text
job text
description text
NOTI_ID text
created datetime
updated datetime
// value field
cat_name text // changed from varchar to text
cat_image text // changed from varchar to text
init_answer json // new field
}
// stores all questions of matching frenzy
Table QuizMatchings {
// system field
id text [pk] // changed from int to text
created datetime [default: `now()`] // record create time
updated datetime // record update time
// value field
word text // changed from varchar to text
word_c text // changed from varchar to text
cat_id text [ref: > QuizCategories.id] // changed type and reference
}
// QuizListening stores all listening quiz data
Table QuizListenings {
// system field
id text [pk] // changed from int to text
created datetime [default: `now()`] // record create time
updated datetime // record update time
// value field
sound file // changed from varchar to file
word text // changed from varchar to text
cat_id text [ref: > QuizCategories.id] // changed type and reference
}
// stores all categories of connectives revision quiz
Table QuizConnectivesCategories {
// system field
id text [pk] // changed from int to text
created datetime [default: `now()`] // record create time
updated datetime // record update time
// value field
cat_name text // changed from varchar to text
cat_image file // changed from varchar to file
}
// stores all questions of connectives revision quiz
Table QuizConnectives {
// system field
id text [pk] // changed from int to text
created datetime [default: `now()`] // record create time
updated datetime // record update time
// value field
question_fh text // changed from varchar to text
question_sh text // changed from varchar to text
modal_ans text // changed from varchar to text
cat_id text [ref: > QuizConnectivesCategories.id] // changed type and reference
}
// Lessons stores all lessons in the database
Table Vocabularies {
// system field
id text [pk] // changed from int to text
created datetime [default: `now()`] // timestamp when the lesson was created
updated datetime // timestamp when the lesson was last updated
// value field
image file // changed from varchar to file
sound file // changed from varchar to file
word text // changed from varchar to text
word_c text // changed from varchar to text
sample_e text // changed from varchar to text
sample_c text // changed from varchar to text
cat_id text [ref: > LessonCategories.id] // changed type and reference
category text // changed from varchar to text
lesson_type_id text [ref: > LessonTypes.id] // changed type and reference
}
// Listening Practice Quiz Categories
// store listening practice category, (LpCategories, LpCategory)
Table QuizLPCategories {
// system fields
id text [pk]
created datetime [default: `now()`]
updated datetime
// value fields
//
// collection id: pbc_4061499106
// collection name: QuizCRCategories
// collection type: base
Table QuizCRCategories {
id text [pk, not null]
cat_name text
cat_image file
pos number
init_answer json
pos integer
init_answer text
created datetime
updated datetime
}
//
// collection id: pbc_3141885671
// collection name: QuizCRQuestions
// collection type: base
Table QuizCRQuestions {
id text [pk, not null]
question_fh text
question_sh text
modal_ans text
cat_id integer [ref: > QuizCRCategories.id] // relation1827623476
options text
created datetime
updated datetime
init_answer text
}
//
// collection id: pbc_3571292172
// collection name: QuizCategories
// collection type: base
Table QuizCategories {
id text [pk, not null]
cat_name text
cat_image text
init_answer text
created datetime
updated datetime
}
//
// collection id: pbc_96745150
// collection name: QuizConnectives
// collection type: base
Table QuizConnectives {
id text [pk, not null]
question_fh text
question_sh text
modal_ans text
cat_id integer [ref: > QuizConnectivesCategories.id] // relation3870140739
created datetime
updated datetime
}
//
// collection id: pbc_342761728
// collection name: QuizConnectivesCategories
// collection type: base
Table QuizConnectivesCategories {
id text [pk, not null]
cat_name text
cat_image file
created datetime
updated datetime
}
//
// collection id: pbc_3639453778
// collection name: QuizLPCategories
// collection type: base
Table QuizLPCategories {
id text [pk, not null]
cat_name text
cat_image file
pos integer
init_answer text
created datetime
updated datetime
visible text
slug text
remarks text
description text
}
// Listening Practice Quiz Questions
//
// collection id: pbc_742947356
// collection name: QuizLPQuestions
// collection type: base
Table QuizLPQuestions {
id text [pk] // changed from int to text
created datetime [default: `now()`]
id text [pk, not null]
word text
sound file
cat_id integer [ref: > QuizLPCategories.id] // relation3870140739
created datetime
updated datetime
word text // changed from varchar to text
sound file // changed from blob to file
cat_id text [ref: > QuizLPCategories.id] // changed type and reference
cat_name text // new field
cat_image file // new field
pos number // new field
init_answer json // new field
visible text // new field
slug text // new field
remarks text // new field
description text // new field
}
// Matching Frenzy Quiz Categories
Table QuizMFCategories {
id text [pk] // changed from int to text
created datetime [default: `now()`]
updated datetime
cat_name text // changed from varchar to text
cat_image file // changed from blob to file
pos number // changed from integer to number
init_answer json
visible text // new field
}
// Matching Frenzy Quiz Questions
Table QuizMFQuestions {
id text [pk] // changed from int to text
created datetime [default: `now()`]
updated datetime
word text // changed from varchar to text
word_c text // changed from varchar to text
cat_id text [ref: > QuizMFCategories.id] // changed type and reference
visible text // new field
sound file // new field
cat_image file // new field
}
// Connectives Revision Quiz Categories
Table QuizCRCategories {
id text [pk] // changed from int to text
created datetime [default: `now()`]
updated datetime
cat_name text // changed from varchar to text
cat_image file // changed from blob to file
cat_name text
cat_image file
pos integer
init_answer json
init_answer text
visible text
slug text
remarks text
description text
}
// Connectives Revision Quiz Questions
Table QuizCRQuestions {
id text [pk] // changed from int to text
created datetime [default: `now()`]
//
// collection id: pbc_2511066072
// collection name: QuizListenings
// collection type: base
Table QuizListenings {
id text [pk, not null]
sound file
word text
cat_id integer [ref: > QuizCategories.id] // relation3870140739
created datetime
updated datetime
question_fh text // changed from varchar to text
question_sh text // changed from varchar to text
modal_ans text // changed from varchar to text
cat_id text [ref: > QuizCRCategories.id] // changed type and reference
options json // new field
}
// Test table
Table t1 {
id text [pk] // changed from int to text
created datetime [default: `now()`]
//
// collection id: pbc_84667061
// collection name: QuizMFCategories
// collection type: base
Table QuizMFCategories {
id text [pk, not null]
cat_name text
cat_image file
pos integer
init_answer text
created datetime
updated datetime
hello text // changed from name to hello
test_file file // new field
visible text
}
// Customers table
Table Customers {
id text [pk] // new table
created datetime [default: `now()`]
//
// collection id: pbc_3346420851
// collection name: QuizMFQuestions
// collection type: base
Table QuizMFQuestions {
id text [pk, not null]
word text
word_c text
cat_id integer [ref: > QuizMFCategories.id] // relation3870140739
created datetime
updated datetime
visible text
sound file
cat_image file
init_answer text
}
//
// collection id: pbc_2936646783
// collection name: QuizMatchings
// collection type: base
Table QuizMatchings {
id text [pk, not null]
word text
word_c text
cat_id integer [ref: > QuizCategories.id] // relation3870140739
created datetime
updated datetime
}
//
// collection id: pbc_491894781
// collection name: Students
// collection type: base
Table Students {
id text [pk, not null]
name text
email text
phone text
quota number
quota integer
status text
avatar_file file
cat_id text [ref: > QuizMFCategories.id] // refer to a single user in `Users` table
user_id integer [ref: > users.id] // relation2809058197
billingAddress text
timezone text
language text
currency text
created datetime
updated datetime
}
//
// collection id: pbc_1413424569
// collection name: Teachers
// collection type: base
Table Teachers {
id text [pk, not null]
name text
email text
phone text
quota integer
status text
avatar_file file
user_id integer [ref: > users.id] // relation2809058197
billingAddress text
timezone text
language text
currency text
created datetime
updated datetime
}
//
// collection id: pbc_1305841361
// collection name: UserMetas
// collection type: base
Table UserMetas {
id text [pk, not null]
helloworld text
meta text
user_id integer [ref: > users.id] // relation2809058197
created datetime
updated datetime
status text
avatar file
role text
name text
email text
phone text
avatar_file file
}
//
// collection id: pbc_1638686383
// collection name: Vocabularies
// collection type: base
Table Vocabularies {
id text [pk, not null]
image file
sound file
word text
word_c text
sample_e text
sample_c text
cat_id integer [ref: > Categories.id] // relation3870140739
category text
lesson_type_id integer [ref: > LessonsTypes.id] // relation808508980
created datetime
updated datetime
visible text
type text
}
//
// collection id: pbc_4275539003
// collection name: _authOrigins
// collection type: base
Table _authOrigins {
id text [pk, not null]
collectionRef text [not null]
recordRef text [not null]
fingerprint text [not null]
created datetime
updated datetime
}
//
// collection id: pbc_2281828961
// collection name: _externalAuths
// collection type: base
Table _externalAuths {
id text [pk, not null]
collectionRef text [not null]
recordRef text [not null]
provider text [not null]
providerId text [not null]
created datetime
updated datetime
}
//
// collection id: pbc_2279338944
// collection name: _mfas
// collection type: base
Table _mfas {
id text [pk, not null]
collectionRef text [not null]
recordRef text [not null]
method text [not null]
created datetime
updated datetime
}
//
// collection id: pbc_1638494021
// collection name: _otps
// collection type: base
Table _otps {
id text [pk, not null]
collectionRef text [not null]
recordRef text [not null]
password varchar [not null]
sentTo text
created datetime
updated datetime
}
//
// collection id: pbc_1509025625
// collection name: billingAddress
// collection type: base
Table billingAddress {
id text [pk, not null]
country text
state text
city text
zipCode text
line1 text
line2 text
created datetime
updated datetime
}
//
// collection id: pbc_123408445
// collection name: helloworlds
// collection type: base
Table helloworlds {
id text [pk, not null]
hello text
created datetime
updated datetime
}
//
// collection id: pbc_2109205374
// collection name: t1
// collection type: base
Table t1 {
id text [pk, not null]
hello text
created datetime
updated datetime
test_file file
}

View File

@@ -1,215 +0,0 @@
// LessonTypes stores different types of lessons
// lesson_types, lesson_type
Table LessonTypes {
// system field
id int [pk, increment] // unique identifier for the lesson type
created datetime [default: `now()`] // timestamp when the lesson type was created
updated datetime // timestamp when the lesson type was last updated
// value field
name varchar // name of the lesson type
type varchar // type category
}
// LessonCategories stores categories of lessons
// lesson_categories, lesson_category
Table LessonCategories {
// system field
id int [pk, increment] // unique identifier for the lesson category
created datetime [default: `now()`] // timestamp when the category was created
updated datetime // timestamp when the category was last updated
// value field
cat_name varchar // image file name
cat_image varchar // image representing the category
lesson_type_id integer [ref: > LessonTypes.id] // foreign key referencing LessonTypes.id
}
Table Helloworlds {
// system field
id int [pk, increment] // id field, increment
created datetime [default: `now()`] // record create time
updated datetime // record update time
}
Table Users {
// system field
id int [pk, increment]
created datetime [default: `now()`]
updated datetime
// value field
email varchar
emailVisibility boolean
verified boolean
name varchar
avatar blob
}
Table UserMetas {
// system field
id int [pk, increment]
created datetime [default: `now()`]
updated datetime
// value field
helloworld varchar
app_on_time_s integer
user_id integer [ref: > Users.id]
}
Table QuizCategories {
// system field
id int [pk, increment]
created datetime [default: `now()`]
updated datetime
// value field
cat_name varchar // category name
cat_image varchar // category image
}
// stores all questions of matching frenzy
Table QuizMatchings {
// system field
id int [pk, increment] // id field, increment
created datetime [default: `now()`] // record create time
updated datetime // record update time
// value field
word varchar // modal answer
word_c varchar // question
cat_id integer [ref: > QuizCategories.id] // foreign key to QuizCategories.id
}
// QuizListening stores all listening quiz data
Table QuizListenings {
// system field
id int [pk, increment] // id field, increment
created datetime [default: `now()`] // record create time
updated datetime // record update time
// value field
sound varchar // URL to the sound file
word varchar // The word in the quiz
cat_id integer [ref: > QuizCategories.id]
}
// stores all categories of connectives revision quiz
Table QuizConnectivesCategories {
// system field
id int [pk, increment] // id field, increment
created datetime [default: `now()`] // record create time
updated datetime // record update time
// value field
cat_name varchar // category name
cat_image varchar // category image
}
// stores all questions of connectives revision quiz
Table QuizConnectives {
// system field
id int [pk, increment] // id field, increment
created datetime [default: `now()`] // record create time
updated datetime // record update time
// value field
question_fh varchar // first half
question_sh varchar // second half
modal_ans varchar // modal ans
cat_id integer [ref: > QuizConnectivesCategories.id] // foreign key to QuizConnectivesCategories.id
}
// Lessons stores all lessons in the database
Table Vocabularies {
// system field
id int [pk, increment] // unique identifier for the lesson
created datetime [default: `now()`] // timestamp when the lesson was created
updated datetime // timestamp when the lesson was last updated
// value field
image varchar // URL to the image associated with the lesson
sound varchar // URL to the sound file associated with the lesson
word varchar // The word in English
word_c varchar // The word in Chinese
sample_e varchar // Sample sentence in English using the word
sample_c varchar // Sample sentence in Chinese using the word
cat_id integer [ref: > LessonCategories.id] // foreign key referring to LessonCategories.id
category varchar // The category to which the lesson belongs
lesson_type_id integer [ref: > LessonTypes.id] // foreign key referring to LessonTypes.id
}
// Listening Practice Quiz Categories
// store listening practice category, (LpCategories, LpCategory)
Table QuizLPCategories {
// system fields
id text [pk] // changed from int to text to match PocketBase
created datetime [default: `now()`]
updated datetime
// value fields
cat_name varchar [presentable: true] // added presentable flag
cat_image file // changed from blob to file type
pos number // changed from integer to number
init_answer json
}
// Listening Practice Quiz Questions
Table QuizLPQuestions {
id int [pk, increment]
created datetime [default: `now()`]
updated datetime
word varchar
sound blob
cat_id integer [ref: > QuizLPCategories.id]
}
// Matching Frenzy Quiz Categories
Table QuizMFCategories {
id int [pk, increment]
created datetime [default: `now()`]
updated datetime
cat_name varchar
cat_image blob
pos integer
init_answer json
}
// Matching Frenzy Quiz Questions
Table QuizMFQuestions {
id int [pk, increment]
created datetime [default: `now()`]
updated datetime
word varchar
word_c varchar
cat_id integer [ref: > QuizMFCategories.id]
}
// Connectives Revision Quiz Categories
Table QuizCRCategories {
id int [pk, increment]
created datetime [default: `now()`]
updated datetime
cat_name varchar
cat_image blob
pos integer
init_answer json
}
// Connectives Revision Quiz Questions
Table QuizCRQuestions {
id int [pk, increment]
created datetime [default: `now()`]
updated datetime
question_fh varchar
question_sh varchar
modal_ans varchar
cat_id integer [ref: > QuizCRCategories.id]
}
// Test table
Table t1 {
id int [pk, increment]
created datetime [default: `now()`]
updated datetime
name varchar
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
---
tags: cms
---
# cms dashboard
cms
## files
T.B.A.

View File

@@ -0,0 +1,11 @@
---
tags: mobile
---
# mobile client
mobile
## files
T.B.A.

View File

@@ -0,0 +1,86 @@
//
// # REQ0015:
// ## PURPOSE:
//
// This is a script to convert `schema.json` exported from pocketbase to dbml formatted file `schema.dbml`
//
//
const fs = require("fs");
const path = require("path");
// Load schema.json
const schemaPath = path.join(process.cwd(), "schema.json");
const schema = JSON.parse(fs.readFileSync(schemaPath, "utf8"));
// Type mapping from PocketBase to DBML/SQL
const typeMapping = {
text: "text",
number: "integer",
bool: "boolean",
email: "text",
url: "varchar",
date: "datetime",
select: "varchar",
json: "text",
file: "file",
password: "varchar",
relation: "integer", // Assuming relations are stored as integer IDs
autodate: "datetime",
};
function convertToDBML(schema) {
let dbml = "";
dbml = "// Generated at: " + new Date().toISOString();
dbml = dbml + "\n\n\n";
let collectionIdToTableMapping = {};
for (const [idx, tableDef] of Object.entries(schema)) {
collectionIdToTableMapping[tableDef.id] = tableDef.name;
}
for (const [idx, tableDef] of Object.entries(schema)) {
console.log({ idx });
dbml += `// \n`;
dbml += `// collection id: ${tableDef.id} \n`;
dbml += `// collection name: ${tableDef.name} \n`;
dbml += `// collection type: ${tableDef.type} \n`;
dbml += `Table ${tableDef.name} {\n`;
for (const field of tableDef.fields) {
// Get field type
let fieldType = typeMapping[field.type] || "text";
// Handle special cases
if (field.type === "number" && field.options?.max === 1) {
fieldType = "boolean";
}
// Build field definition
let line = ` ${field.name} ${fieldType}`;
// Add constraints
const constraints = [];
if (field.name === "id" || field.primary) constraints.push("pk");
if (field.required) constraints.push("not null");
if (constraints.length > 0) line += ` [${constraints.join(", ")}]`;
if (field.collectionId) {
line += ` [ref: > ${
collectionIdToTableMapping[field.collectionId]
}.id] // ${field.id}`;
}
dbml += `${line}\n`;
console.log({ line });
}
dbml += "}\n\n";
}
return dbml;
}
// Convert and save
const dbmlOutput = convertToDBML(schema);
fs.writeFileSync("schema.dbml", dbmlOutput);
console.log("DBML file generated successfully!");

View File

@@ -0,0 +1,9 @@
---
tags: mobile, cms, db, schema
---
# pocketbase json schema to dbml converter
## description
to generate a `schema.dbml` form `schema.json` exported from pocketbase

View File

@@ -0,0 +1,18 @@
// Generated at: 2025-05-06T06:24:44.009Z
//
// collection id: pbc_3142635823
// collection name: helloworld
// collection type: auth
Table helloworld {
id text [pk, not null]
password varchar [not null]
tokenKey text [not null]
email text [not null]
emailVisibility boolean
verified boolean
created datetime
updated datetime
}

View File

@@ -0,0 +1,174 @@
[
{
"id": "pbc_3142635823",
"listRule": null,
"viewRule": null,
"createRule": null,
"updateRule": null,
"deleteRule": null,
"name": "helloworld",
"type": "auth",
"fields": [
{
"autogeneratePattern": "[a-z0-9]{15}",
"hidden": false,
"id": "text3208210256",
"max": 15,
"min": 15,
"name": "id",
"pattern": "^[a-z0-9]+$",
"presentable": false,
"primaryKey": true,
"required": true,
"system": true,
"type": "text"
},
{
"cost": 0,
"hidden": true,
"id": "password901924565",
"max": 0,
"min": 8,
"name": "password",
"pattern": "",
"presentable": false,
"required": true,
"system": true,
"type": "password"
},
{
"autogeneratePattern": "[a-zA-Z0-9]{50}",
"hidden": true,
"id": "text2504183744",
"max": 60,
"min": 30,
"name": "tokenKey",
"pattern": "",
"presentable": false,
"primaryKey": false,
"required": true,
"system": true,
"type": "text"
},
{
"exceptDomains": null,
"hidden": false,
"id": "email3885137012",
"name": "email",
"onlyDomains": null,
"presentable": false,
"required": true,
"system": true,
"type": "email"
},
{
"hidden": false,
"id": "bool1547992806",
"name": "emailVisibility",
"presentable": false,
"required": false,
"system": true,
"type": "bool"
},
{
"hidden": false,
"id": "bool256245529",
"name": "verified",
"presentable": false,
"required": false,
"system": true,
"type": "bool"
},
{
"hidden": false,
"id": "autodate2990389176",
"name": "created",
"onCreate": true,
"onUpdate": false,
"presentable": false,
"system": true,
"type": "autodate"
},
{
"hidden": false,
"id": "autodate3332085495",
"name": "updated",
"onCreate": true,
"onUpdate": true,
"presentable": false,
"system": true,
"type": "autodate"
}
],
"indexes": [
"CREATE UNIQUE INDEX `idx_tokenKey_pbc_3142635823` ON `_superusers` (`tokenKey`)",
"CREATE UNIQUE INDEX `idx_email_pbc_3142635823` ON `_superusers` (`email`) WHERE `email` != ''"
],
"system": true,
"authRule": "",
"manageRule": null,
"authAlert": {
"enabled": true,
"emailTemplate": {
"subject": "Login from a new location",
"body": "<p>Hello,</p>\n<p>We noticed a login to your {APP_NAME} account from a new location.</p>\n<p>If this was you, you may disregard this email.</p>\n<p><strong>If this wasn't you, you should immediately change your {APP_NAME} account password to revoke access from all other locations.</strong></p>\n<p>\n Thanks,<br/>\n {APP_NAME} team\n</p>"
}
},
"oauth2": {
"mappedFields": {
"id": "",
"name": "",
"username": "",
"avatarURL": ""
},
"enabled": false
},
"passwordAuth": {
"enabled": true,
"identityFields": [
"email"
]
},
"mfa": {
"enabled": false,
"duration": 1800,
"rule": ""
},
"otp": {
"enabled": false,
"duration": 180,
"length": 8,
"emailTemplate": {
"subject": "OTP for {APP_NAME}",
"body": "<p>Hello,</p>\n<p>Your one-time password is: <strong>{OTP}</strong></p>\n<p><i>If you didn't ask for the one-time password, you can ignore this email.</i></p>\n<p>\n Thanks,<br/>\n {APP_NAME} team\n</p>"
}
},
"authToken": {
"duration": 86400
},
"passwordResetToken": {
"duration": 1800
},
"emailChangeToken": {
"duration": 1800
},
"verificationToken": {
"duration": 259200
},
"fileToken": {
"duration": 180
},
"verificationTemplate": {
"subject": "Verify your {APP_NAME} email",
"body": "<p>Hello,</p>\n<p>Thank you for joining us at {APP_NAME}.</p>\n<p>Click on the button below to verify your email address.</p>\n<p>\n <a class=\"btn\" href=\"{APP_URL}/_/#/auth/confirm-verification/{TOKEN}\" target=\"_blank\" rel=\"noopener\">Verify</a>\n</p>\n<p>\n Thanks,<br/>\n {APP_NAME} team\n</p>"
},
"resetPasswordTemplate": {
"subject": "Reset your {APP_NAME} password",
"body": "<p>Hello,</p>\n<p>Click on the button below to reset your password.</p>\n<p>\n <a class=\"btn\" href=\"{APP_URL}/_/#/auth/confirm-password-reset/{TOKEN}\" target=\"_blank\" rel=\"noopener\">Reset password</a>\n</p>\n<p><i>If you didn't ask to reset your password, you can ignore this email.</i></p>\n<p>\n Thanks,<br/>\n {APP_NAME} team\n</p>"
},
"confirmEmailChangeTemplate": {
"subject": "Confirm your {APP_NAME} new email address",
"body": "<p>Hello,</p>\n<p>Click on the button below to confirm your new email address.</p>\n<p>\n <a class=\"btn\" href=\"{APP_URL}/_/#/auth/confirm-email-change/{TOKEN}\" target=\"_blank\" rel=\"noopener\">Confirm new email</a>\n</p>\n<p><i>If you didn't ask to change your email address, you can ignore this email.</i></p>\n<p>\n Thanks,<br/>\n {APP_NAME} team\n</p>"
}
}
]

View File

@@ -0,0 +1,33 @@
---
tags: cms, login-flow
---
# login flow
## description
```mermaid
graph TD;
Start-->A;
A-->B;
B-->C;
B-->D;
D-->E;
E-->F;
C-->G;
G-->A
F-->End;
A[greeting, asking username and password]
B[check if username and password is valid]
C[pasword failed]
D[pasword ok]
E[login success]
F[redirect to '/dashboard']
G[prompt user wrong username and password]
Start((start));
End((end))
```

View File

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 178 KiB

View File

@@ -0,0 +1,9 @@
---
tags: mobile, lesson
---
# lesson page documentation
it should have a lesson page
![alt text](image.png)

View File

@@ -1,50 +1,20 @@
# Requirements Index
## REQ0001: project overview
[View Requirement](./REQ0001/index.md)
## REQ0002: lesson page documentation
[View Requirement](./REQ0002/index.md)
## REQ0003: quiz page documentation
[View Requirement](./REQ0003/index.md)
## REQ0004: record page documentation
[View Requirement](./REQ0004/index.md)
## REQ0005: settings page documentation
[View Requirement](./REQ0005/index.md)
## REQ0006: db schema design
[View Requirement](./REQ0006/index.md)
## REQ0007: testing of mobile app home
[View Requirement](./REQ0007/index.md)
## REQ0008: schema design
[View Requirement](./REQ0008/index.md)
## REQ0009: loading screen
[View Requirement](./REQ0009/index.md)
## REQ0010: user friendly error messages
[View Requirement](./REQ0010/index.md)
## REQ0011: developer friendly error messages
[View Requirement](./REQ0011/index.md)
## REQ0012: cms navigation system
[View Requirement](./REQ0012/index.md)
- [REQ0001: project overview](./REQ0001/index.md)
- [REQ0002: lesson page documentation](./REQ0002/index.md)
- [REQ0003: quiz page documentation](./REQ0003/index.md)
- [REQ0004: record page documentation](./REQ0004/index.md)
- [REQ0005: settings page documentation](./REQ0005/index.md)
- [REQ0006: task](./REQ0006/008_update_dbml_from_json.md)
- [REQ0006: GUIDELINES](./REQ0006/_GUIDELINE.md)
- [REQ0006: db schema design](./REQ0006/index.md)
- [REQ0007: testing of mobile app home](./REQ0007/index.md)
- [REQ0008: schema design](./REQ0008/index.md)
- [REQ0009: loading screen](./REQ0009/index.md)
- [REQ0010: user friendly error messages](./REQ0010/index.md)
- [REQ0011: developer friendly error messages](./REQ0011/index.md)
- [REQ0012: cms navigation system](./REQ0012/index.md)
- [REQ0013: cms dashboard](./REQ0013/index.md)
- [REQ0014: mobile client](./REQ0014/index.md)
- [REQ0015: pocketbase json schema to dbml converter](./REQ0015/index.md)
- [REQ0016: login flow](./REQ0016/index.md)

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -ex
npx nodemon --delay 0.1 --ext md,js --ignore ./index.md --exec "node ./update_req_index.js"

View File

@@ -36,8 +36,8 @@ async function updateIndex() {
const heading = extractH1(content);
if (heading) {
indexContent += `## ${dir}: ${heading}\n\n`;
indexContent += `[View Requirement](./${dir}/${file})\n\n`;
indexContent += `- [${dir}: ${heading}](./${dir}/${file})\n`;
// indexContent += `[View Requirement](./${dir}/${file})\n\n`;
}
}
}