Compare commits

...

2 Commits

Author SHA1 Message Date
a8c85f1b74 pocketbase + script changes 2025-09-25 21:37:19 +01:00
6839bfe316 git ignore 2025-09-25 21:36:29 +01:00
52 changed files with 1029 additions and 1481 deletions

66
.gitignore vendored Normal file
View File

@@ -0,0 +1,66 @@
# PocketBase data and migrations
pb_data/
pb_migrations/
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# Virtual environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Node.js
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# IDEs
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Logs
*.log
logs/
# Temporary files
*.tmp
*.temp

1
node_modules/.package-lock.json generated vendored
View File

@@ -1,5 +1,6 @@
{ {
"name": "personal-tracker", "name": "personal-tracker",
"version": "1.0.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {

3
package-lock.json generated
View File

@@ -1,9 +1,12 @@
{ {
"name": "personal-tracker", "name": "personal-tracker",
"version": "1.0.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "personal-tracker",
"version": "1.0.0",
"dependencies": { "dependencies": {
"pocketbase": "^0.26.2" "pocketbase": "^0.26.2"
} }

View File

@@ -1,7 +1,7 @@
{ {
"name": "personal-tracker", "name": "personal-tracker",
"version": "1.0.0", "version": "1.0.0",
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"pocketbase": "^0.26.2" "pocketbase": "^0.26.2"
} }

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2749400118",
"indexes": [],
"listRule": null,
"name": "semantic_segments",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_2749400118");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_3768126507",
"indexes": [],
"listRule": null,
"name": "frequent_places",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_3768126507");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_1343767521",
"indexes": [],
"listRule": null,
"name": "raw_signals",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_1343767521");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_952801224",
"indexes": [],
"listRule": null,
"name": "timeline_path_points",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_952801224");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_1935361188",
"indexes": [],
"listRule": null,
"name": "visits",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_1935361188");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_1493499684",
"indexes": [],
"listRule": null,
"name": "frequent_trip_mode_distribution",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_1493499684");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2743264166",
"indexes": [],
"listRule": null,
"name": "frequent_trip_waypoints",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_2743264166");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2648794696",
"indexes": [],
"listRule": null,
"name": "frequent_trips",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_2648794696");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2007833242",
"indexes": [],
"listRule": null,
"name": "travel_mode_affinities",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_2007833242");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_3768126507");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_3768126507",
"indexes": [],
"listRule": null,
"name": "frequent_places",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_1493499684");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_1493499684",
"indexes": [],
"listRule": null,
"name": "frequent_trip_mode_distribution",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_2743264166");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2743264166",
"indexes": [],
"listRule": null,
"name": "frequent_trip_waypoints",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_2648794696");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2648794696",
"indexes": [],
"listRule": null,
"name": "frequent_trips",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_1343767521");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_1343767521",
"indexes": [],
"listRule": null,
"name": "raw_signals",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_2749400118");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2749400118",
"indexes": [],
"listRule": null,
"name": "semantic_segments",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_952801224");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_952801224",
"indexes": [],
"listRule": null,
"name": "timeline_path_points",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_2007833242");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2007833242",
"indexes": [],
"listRule": null,
"name": "travel_mode_affinities",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_1935361188");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_1935361188",
"indexes": [],
"listRule": null,
"name": "visits",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2749400118",
"indexes": [],
"listRule": null,
"name": "semantic_segments",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_2749400118");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_3768126507",
"indexes": [],
"listRule": null,
"name": "frequent_places",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_3768126507");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_1343767521",
"indexes": [],
"listRule": null,
"name": "raw_signals",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_1343767521");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_952801224",
"indexes": [],
"listRule": null,
"name": "timeline_path_points",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_952801224");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_1935361188",
"indexes": [],
"listRule": null,
"name": "visits",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_1935361188");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_1493499684",
"indexes": [],
"listRule": null,
"name": "frequent_trip_mode_distribution",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_1493499684");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2743264166",
"indexes": [],
"listRule": null,
"name": "frequent_trip_waypoints",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_2743264166");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2648794696",
"indexes": [],
"listRule": null,
"name": "frequent_trips",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_2648794696");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2007833242",
"indexes": [],
"listRule": null,
"name": "travel_mode_affinities",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_2007833242");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_3768126507");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_3768126507",
"indexes": [],
"listRule": null,
"name": "frequent_places",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_1493499684");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_1493499684",
"indexes": [],
"listRule": null,
"name": "frequent_trip_mode_distribution",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_2743264166");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2743264166",
"indexes": [],
"listRule": null,
"name": "frequent_trip_waypoints",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_2648794696");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2648794696",
"indexes": [],
"listRule": null,
"name": "frequent_trips",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_1343767521");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_1343767521",
"indexes": [],
"listRule": null,
"name": "raw_signals",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_2749400118");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2749400118",
"indexes": [],
"listRule": null,
"name": "semantic_segments",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_952801224");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_952801224",
"indexes": [],
"listRule": null,
"name": "timeline_path_points",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_2007833242");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2007833242",
"indexes": [],
"listRule": null,
"name": "travel_mode_affinities",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_1935361188");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_1935361188",
"indexes": [],
"listRule": null,
"name": "visits",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_1886393167",
"indexes": [],
"listRule": null,
"name": "visits_test",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_1886393167");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = app.findCollectionByNameOrId("pbc_1886393167");
return app.delete(collection);
}, (app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_1886393167",
"indexes": [],
"listRule": null,
"name": "visits_test",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_1665123660",
"indexes": [],
"listRule": null,
"name": "visits_test_v2",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_1665123660");
return app.delete(collection);
})

View File

@@ -1,37 +0,0 @@
/// <reference path="../pb_data/types.d.ts" />
migrate((app) => {
const collection = new Collection({
"createRule": null,
"deleteRule": null,
"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"
}
],
"id": "pbc_2790463832",
"indexes": [],
"listRule": null,
"name": "test_simple",
"system": false,
"type": "base",
"updateRule": null,
"viewRule": null
});
return app.save(collection);
}, (app) => {
const collection = app.findCollectionByNameOrId("pbc_2790463832");
return app.delete(collection);
})

View File

@@ -0,0 +1,643 @@
# PocketBase Integration Guide
# Complete guide for creating schemas and uploading CSV data to PocketBase
## Table of Contents
1. Authentication Setup
2. Collection Schema Creation
3. Data Upload Process
4. Common Issues and Solutions
5. Field Types and Validation
6. Best Practices
7. Code Examples
8. Troubleshooting
================================================================================
## 1. AUTHENTICATION SETUP
================================================================================
### Superuser Authentication Required
- Creating collections requires SUPERUSER authentication (not regular user auth)
- Use the "_superusers" collection for authentication
```javascript
import PocketBase from 'pocketbase';
const pb = new PocketBase('http://localhost:8090');
// CRITICAL: Must authenticate as superuser for collection operations
await pb.collection("_superusers").authWithPassword('your-email@example.com', 'your-password');
```
### Authentication Error Handling
```javascript
try {
await pb.collection("_superusers").authWithPassword('email', 'password');
console.log('Authenticated as superuser');
} catch (error) {
console.error('Failed to authenticate:', error.message);
throw error;
}
```
================================================================================
## 2. COLLECTION SCHEMA CREATION
================================================================================
### Basic Collection Structure
```javascript
const collectionData = {
name: 'collection_name', // Must be unique
type: 'base', // 'base', 'auth', or 'view'
fields: [...], // Array of field definitions
indexes: [...], // Optional database indexes
listRule: '', // API access rules (empty = public)
viewRule: '',
createRule: '',
updateRule: '',
deleteRule: ''
};
```
### Field Types and Properties
```javascript
// TEXT FIELD
{
name: 'field_name',
type: 'text',
required: false, // IMPORTANT: Use false for optional fields
max: 255 // Maximum character length
}
// NUMBER FIELD
{
name: 'numeric_field',
type: 'number',
required: false // CRITICAL: Set to false if field can be 0 or null
}
// DATE FIELD
{
name: 'date_field',
type: 'date',
required: true
}
// BOOLEAN FIELD
{
name: 'boolean_field',
type: 'bool',
required: false
}
```
### Database Indexes (Optional but Recommended)
```javascript
indexes: [
'CREATE INDEX idx_tablename_field ON tablename (field_name)',
'CREATE INDEX idx_tablename_date ON tablename (date_field)',
'CREATE INDEX idx_tablename_composite ON tablename (field1, field2)'
]
```
### Complete Collection Creation Example
```javascript
async function createCollection() {
const pb = new PocketBase('http://localhost:8090');
await pb.collection("_superusers").authWithPassword('email', 'password');
const collectionData = {
name: 'visits',
type: 'base',
fields: [
{
name: 'segment_index',
type: 'number',
required: true
},
{
name: 'hierarchyLevel',
type: 'number',
required: false // IMPORTANT: Allow 0 values
},
{
name: 'visit_probability',
type: 'number',
required: true
},
{
name: 'top_place_id',
type: 'text',
required: false,
max: 255
},
{
name: 'startTime',
type: 'date',
required: true
}
],
indexes: [
'CREATE INDEX idx_visits_segment_index ON visits (segment_index)',
'CREATE INDEX idx_visits_start_time ON visits (startTime)'
]
};
try {
const collection = await pb.collections.create(collectionData);
console.log('Collection created:', collection.name);
} catch (error) {
if (error.message.includes('already exists')) {
console.log('Collection already exists');
} else {
throw error;
}
}
}
```
================================================================================
## 3. DATA UPLOAD PROCESS
================================================================================
### CSV File Reading and Parsing
```javascript
import fs from 'fs';
// Read CSV file
const csvData = fs.readFileSync('/path/to/file.csv', 'utf8');
const lines = csvData.trim().split('\n');
// CRITICAL: Clean headers to remove carriage returns and whitespace
const headers = lines[0].split(',').map(h => h.trim().replace(/\r$/, ''));
```
### CSV Line Parsing (Handle Quoted Fields)
```javascript
function parseCsvLine(line) {
const result = [];
let current = '';
let inQuotes = false;
for (let i = 0; i < line.length; i++) {
const char = line[i];
if (char === '"') {
inQuotes = !inQuotes;
} else if (char === ',' && !inQuotes) {
result.push(current.trim());
current = '';
} else {
current += char;
}
}
result.push(current.trim());
return result;
}
```
### Data Type Conversion (CRITICAL)
```javascript
// Process each row
const record = {};
headers.forEach((header, index) => {
const value = values[index];
switch (header) {
case 'segment_index':
case 'hierarchyLevel':
// IMPORTANT: Check for empty string, not falsy values
record[header] = value !== '' ? parseInt(value) : null;
break;
case 'visit_probability':
case 'top_probability':
case 'top_lat':
case 'top_lon':
record[header] = value !== '' ? parseFloat(value) : null;
break;
case 'startTime':
case 'endTime':
// Convert to ISO string format
record[header] = value ? new Date(value).toISOString() : null;
break;
default:
record[header] = value || null;
}
});
```
### Batch Upload with Error Handling
```javascript
async function uploadData() {
const pb = new PocketBase('http://localhost:8090');
await pb.collection("_superusers").authWithPassword('email', 'password');
let successCount = 0;
let errorCount = 0;
for (let i = 1; i < lines.length; i++) { // Skip header row
const values = parseCsvLine(lines[i]);
// Create record object (see data type conversion above)
const record = { ... };
try {
await pb.collection('collection_name').create(record);
successCount++;
if (successCount % 100 === 0) {
console.log(`Uploaded ${successCount} records...`);
}
} catch (error) {
console.error(`Row ${i} failed:`, error.message);
// Log detailed PocketBase error
if (error.response && error.response.data) {
console.error(`PocketBase error:`, JSON.stringify(error.response.data, null, 2));
}
errorCount++;
}
}
console.log(`Success: ${successCount}, Errors: ${errorCount}`);
}
```
================================================================================
## 4. COMMON ISSUES AND SOLUTIONS
================================================================================
### Issue 1: "Cannot be blank" for Zero Values
PROBLEM: PocketBase treats 0 as blank for required number fields
SOLUTION: Set number fields to required: false, handle validation in app logic
```javascript
// WRONG
{
name: 'hierarchyLevel',
type: 'number',
required: true // This will reject 0 values
}
// CORRECT
{
name: 'hierarchyLevel',
type: 'number',
required: false // Allows 0 values
}
```
### Issue 2: Carriage Return in CSV Headers
PROBLEM: CSV files may have \r characters in headers
SOLUTION: Clean headers when parsing
```javascript
// Clean headers
const headers = lines[0].split(',').map(h => h.trim().replace(/\r$/, ''));
```
### Issue 3: Date Format Issues
PROBLEM: Date strings not recognized by PocketBase
SOLUTION: Convert to ISO format
```javascript
// Convert any date string to ISO format
record[header] = value ? new Date(value).toISOString() : null;
```
### Issue 4: Authentication Errors
PROBLEM: Using wrong authentication method
SOLUTION: Always use _superusers collection for admin operations
```javascript
// WRONG
await pb.collection("users").authWithPassword(...);
// CORRECT
await pb.collection("_superusers").authWithPassword(...);
```
### Issue 5: Collection Already Exists
PROBLEM: Script fails when collection exists
SOLUTION: Handle the error gracefully
```javascript
try {
await pb.collections.create(collectionData);
} catch (error) {
if (error.message.includes('already exists')) {
console.log('Collection already exists');
} else {
throw error;
}
}
```
================================================================================
## 5. FIELD TYPES AND VALIDATION
================================================================================
### Available Field Types
- text: String values (max length configurable)
- number: Integer or float values
- bool: Boolean true/false
- date: ISO date strings
- json: JSON objects
- file: File uploads
- relation: References to other collections
- select: Predefined options
- autodate: Auto-generated timestamps
### Validation Rules
```javascript
// Text field with validation
{
name: 'email',
type: 'text',
required: true,
pattern: '^[\\w\\.-]+@[\\w\\.-]+\\.[a-zA-Z]{2,}$', // Email regex
max: 255
}
// Number field with min/max
{
name: 'age',
type: 'number',
required: false,
min: 0,
max: 150
}
// Select field with options
{
name: 'status',
type: 'select',
required: true,
values: ['active', 'inactive', 'pending']
}
```
================================================================================
## 6. BEST PRACTICES
================================================================================
### Schema Design
1. Use descriptive field names (snake_case or camelCase consistently)
2. Set required: false for fields that can be 0, null, or empty
3. Add appropriate indexes for frequently queried fields
4. Use appropriate field types (don't store numbers as text)
5. Set reasonable max lengths for text fields
### Data Upload
1. Always authenticate as superuser for admin operations
2. Parse CSV data carefully, handling quotes and special characters
3. Convert data types explicitly before uploading
4. Use batch processing with progress logging
5. Implement proper error handling and logging
6. Validate data before uploading when possible
### Error Handling
1. Log detailed error messages including PocketBase responses
2. Handle common errors gracefully (collection exists, auth failures)
3. Stop processing after multiple consecutive errors to debug
4. Provide meaningful error messages for troubleshooting
### Performance
1. Use database indexes for frequently queried fields
2. Process uploads in batches with progress indicators
3. Consider using transactions for large data sets
4. Monitor memory usage for very large CSV files
================================================================================
## 7. COMPLETE CODE EXAMPLES
================================================================================
### Collection Creation Script Template
```javascript
import PocketBase from 'pocketbase';
async function createMyCollection() {
const pb = new PocketBase('http://localhost:8090');
// Authenticate
try {
await pb.collection("_superusers").authWithPassword('your-email', 'your-password');
console.log('Authenticated as superuser');
} catch (error) {
console.error('Authentication failed:', error.message);
throw error;
}
const collectionData = {
name: 'your_collection_name',
type: 'base',
fields: [
// Define your fields here based on CSV structure
],
indexes: [
// Add indexes for performance
],
listRule: '', // Set access rules as needed
viewRule: '',
createRule: '',
updateRule: '',
deleteRule: ''
};
try {
const collection = await pb.collections.create(collectionData);
console.log('Collection created successfully:', collection.name);
return collection;
} catch (error) {
if (error.message.includes('already exists')) {
console.log('Collection already exists');
} else {
console.error('Error creating collection:', error);
throw error;
}
}
}
// Export for use in other scripts
export { createMyCollection };
// Run if called directly
if (import.meta.url === `file://${process.argv[1]}`) {
createMyCollection()
.then(() => {
console.log('Script completed successfully');
process.exit(0);
})
.catch((error) => {
console.error('Script failed:', error);
process.exit(1);
});
}
```
### Data Upload Script Template
```javascript
import PocketBase from 'pocketbase';
import fs from 'fs';
async function uploadDataToCollection() {
const pb = new PocketBase('http://localhost:8090');
// Authenticate
await pb.collection("_superusers").authWithPassword('your-email', 'your-password');
// Read CSV
const csvPath = '/path/to/your/data.csv';
const csvData = fs.readFileSync(csvPath, 'utf8');
const lines = csvData.trim().split('\n');
const headers = lines[0].split(',').map(h => h.trim().replace(/\r$/, ''));
console.log(`Found ${lines.length - 1} rows to upload`);
console.log('Headers:', headers);
let successCount = 0;
let errorCount = 0;
// Process each row
for (let i = 1; i < lines.length; i++) {
const values = parseCsvLine(lines[i]);
if (values.length !== headers.length) {
console.warn(`Row ${i}: Column count mismatch, skipping`);
errorCount++;
continue;
}
// Build record object
const record = {};
headers.forEach((header, index) => {
const value = values[index];
// Customize data type conversion based on your schema
switch (header) {
case 'id_field':
case 'count_field':
record[header] = value !== '' ? parseInt(value) : null;
break;
case 'decimal_field':
case 'percentage_field':
record[header] = value !== '' ? parseFloat(value) : null;
break;
case 'date_field':
case 'timestamp_field':
record[header] = value ? new Date(value).toISOString() : null;
break;
default:
record[header] = value || null;
}
});
// Upload record
try {
await pb.collection('your_collection_name').create(record);
successCount++;
if (successCount % 100 === 0) {
console.log(`Uploaded ${successCount} records...`);
}
} catch (error) {
console.error(`Row ${i} failed:`, error.message);
if (error.response && error.response.data) {
console.error(`Details:`, JSON.stringify(error.response.data, null, 2));
}
errorCount++;
// Stop after too many errors to debug
if (errorCount >= 5) {
console.log('Too many errors, stopping to debug...');
break;
}
}
}
console.log(`\nUpload completed:`);
console.log(`Success: ${successCount} records`);
console.log(`Errors: ${errorCount} records`);
}
function parseCsvLine(line) {
const result = [];
let current = '';
let inQuotes = false;
for (let i = 0; i < line.length; i++) {
const char = line[i];
if (char === '"') {
inQuotes = !inQuotes;
} else if (char === ',' && !inQuotes) {
result.push(current.trim());
current = '';
} else {
current += char;
}
}
result.push(current.trim());
return result;
}
export { uploadDataToCollection };
```
================================================================================
## 8. TROUBLESHOOTING CHECKLIST
================================================================================
### Before Running Scripts
□ PocketBase server is running on correct port (default: 8090)
□ Superuser account exists with correct credentials
□ CSV file path is correct and file is accessible
□ Node.js modules are installed (npm install pocketbase)
□ Project is configured for ES modules (package.json has "type": "module")
### If Collection Creation Fails
□ Check authentication credentials
□ Verify collection name doesn't already exist
□ Ensure field definitions are valid
□ Check for typos in field types ('number' not 'Number')
□ Verify required vs optional field settings
### If Data Upload Fails
□ Collection exists and schema matches CSV structure
□ CSV headers are clean (no carriage returns)
□ Data types are being converted correctly
□ Check for null/empty value handling
□ Verify date formats are valid
□ Look at detailed PocketBase error messages
### Common Error Messages
- "Cannot be blank": Field is required but receiving null/0/empty value
- "Failed to create record": Generic error, check detailed error response
- "The request requires valid record authorization token": Authentication failed
- "Collection not found": Typo in collection name or collection doesn't exist
### Performance Issues
□ Add database indexes for frequently queried fields
□ Process large files in smaller batches
□ Monitor memory usage with very large CSVs
□ Consider using database transactions for consistency
================================================================================
## FINAL NOTES
================================================================================
1. Always test with a small subset of data first
2. Keep backups of your CSV files before processing
3. Monitor PocketBase logs for additional error details
4. Use version control for your scripts
5. Document any custom data transformations needed for your specific use case
6. Consider creating utility functions for common operations
7. Test error scenarios (network issues, invalid data, etc.)
Remember: PocketBase validation is strict. It's better to be permissive in your schema
and validate in your application logic than to fight with PocketBase's validation rules.

View File

@@ -0,0 +1,113 @@
import PocketBase from 'pocketbase';
async function createVisitsCollection() {
const pb = new PocketBase('http://localhost:8090');
// Authenticate as superuser (required for creating collections)
try {
await pb.collection("_superusers").authWithPassword('azeem.fidahusein@gmail.com', 'azsxdcazsxdc');
console.log('Authenticated as superuser');
} catch (error) {
console.error('Failed to authenticate as superuser:', error.message);
console.error('Make sure your PocketBase instance has a superuser with email "test@example.com" and password "1234567890"');
throw error;
}
const collectionData = {
name: 'visits',
type: 'base',
fields: [
{
name: 'segment_index',
type: 'number',
required: true
},
{
name: 'hierarchyLevel',
type: 'number',
required: false
},
{
name: 'visit_probability',
type: 'number',
required: true
},
{
name: 'top_place_id',
type: 'text',
required: false,
max: 255
},
{
name: 'top_semantic_type',
type: 'text',
required: false,
max: 100
},
{
name: 'top_probability',
type: 'number',
required: false
},
{
name: 'top_lat',
type: 'number',
required: false
},
{
name: 'top_lon',
type: 'number',
required: false
},
{
name: 'startTime',
type: 'date',
required: true
},
{
name: 'endTime',
type: 'date',
required: true
}
],
indexes: [
'CREATE INDEX idx_visits_segment_index ON visits (segment_index)',
'CREATE INDEX idx_visits_start_time ON visits (startTime)',
'CREATE INDEX idx_visits_place_id ON visits (top_place_id)'
],
listRule: '',
viewRule: '',
createRule: '',
updateRule: '',
deleteRule: ''
};
try {
console.log('Creating visits collection...');
const collection = await pb.collections.create(collectionData);
console.log('Collection created successfully:', collection.name);
return collection;
} catch (error) {
if (error.message.includes('already exists')) {
console.log('Collection "visits" already exists');
} else {
console.error('Error creating collection:', error);
throw error;
}
}
}
// Check if this file is being run directly
if (import.meta.url === `file://${process.argv[1]}`) {
createVisitsCollection()
.then(() => {
console.log('Script completed successfully');
process.exit(0);
})
.catch((error) => {
console.error('Script failed:', error);
process.exit(1);
});
}
export { createVisitsCollection };

View File

@@ -0,0 +1,65 @@
import PocketBase from 'pocketbase';
async function deleteAllCollections() {
const pb = new PocketBase('http://localhost:8090');
// Authenticate as superuser (required for deleting collections)
try {
await pb.collection("_superusers").authWithPassword('admin@example.com', 'azsxdcazsxdc');
console.log('Authenticated as superuser');
} catch (error) {
console.error('Failed to authenticate as superuser:', error.message);
throw error;
}
try {
console.log('Fetching all collections...');
const collections = await pb.collections.getFullList();
console.log(`Found ${collections.length} collections to delete`);
for (const collection of collections) {
try {
console.log(`Deleting records from collection: ${collection.name}`);
// Get all records from the collection
const records = await pb.collection(collection.name).getFullList();
console.log(` Found ${records.length} records in ${collection.name}`);
// Delete all records
for (const record of records) {
await pb.collection(collection.name).delete(record.id);
}
console.log(` Deleted all records from ${collection.name}`);
// Delete the collection itself
await pb.collections.delete(collection.id);
console.log(`✓ Deleted collection: ${collection.name}`);
} catch (error) {
console.error(`Error deleting collection ${collection.name}:`, error.message);
}
}
console.log('All collections and records deleted successfully');
} catch (error) {
console.error('Error fetching collections:', error);
throw error;
}
}
// Check if this script is being run directly
if (import.meta.url === `file://${process.argv[1]}`) {
deleteAllCollections()
.then(() => {
console.log('Script completed successfully');
process.exit(0);
})
.catch((error) => {
console.error('Script failed:', error);
process.exit(1);
});
}
export { deleteAllCollections };

View File

@@ -0,0 +1,137 @@
import PocketBase from 'pocketbase';
import fs from 'fs';
import path from 'path';
async function uploadVisitsData() {
const pb = new PocketBase('http://localhost:8090');
// Authenticate as superuser
try {
await pb.collection("_superusers").authWithPassword('azeem.fidahusein@gmail.com', 'azsxdcazsxdc');
console.log('Authenticated as superuser');
} catch (error) {
console.error('Failed to authenticate as superuser:', error.message);
throw error;
}
// Read and parse CSV file
const csvPath = '/Users/azeem/repos/personal-tracker/data/timeline_csv/visits.csv';
try {
const csvData = fs.readFileSync(csvPath, 'utf8');
const lines = csvData.trim().split('\n');
const headers = lines[0].split(',').map(h => h.trim().replace(/\r$/, ''));
console.log(`Found ${lines.length - 1} rows to upload`);
console.log('Headers:', headers);
let successCount = 0;
let errorCount = 0;
// Process each row (skip header)
for (let i = 1; i < lines.length; i++) {
const values = parseCsvLine(lines[i]);
if (values.length !== headers.length) {
console.warn(`Row ${i}: Column count mismatch, skipping`);
errorCount++;
continue;
}
// Create record object
const record = {};
headers.forEach((header, index) => {
const value = values[index];
// Handle different data types based on field name
switch (header) {
case 'segment_index':
case 'hierarchyLevel':
record[header] = value !== '' ? parseInt(value) : null;
break;
case 'visit_probability':
case 'top_probability':
case 'top_lat':
case 'top_lon':
record[header] = value !== '' ? parseFloat(value) : null;
break;
case 'startTime':
case 'endTime':
// Convert ISO string to proper date format
record[header] = value ? new Date(value).toISOString() : null;
break;
default:
record[header] = value || null;
}
});
try {
await pb.collection('visits').create(record);
successCount++;
if (successCount % 100 === 0) {
console.log(`Uploaded ${successCount} records...`);
}
} catch (error) {
console.error(`Row ${i} failed:`, error.message);
if (error.response && error.response.data) {
console.error(`PocketBase error:`, JSON.stringify(error.response.data, null, 2));
}
console.error(`Record data:`, JSON.stringify(record, null, 2));
errorCount++;
// Stop after first few errors to debug
if (errorCount >= 3) {
console.log('Stopping after 3 errors to debug...');
break;
}
}
}
console.log(`\nUpload completed:`);
console.log(`Success: ${successCount} records`);
console.log(`Errors: ${errorCount} records`);
} catch (error) {
console.error('Error reading CSV file:', error.message);
throw error;
}
}
// Helper function to parse CSV line properly (handles commas in quoted fields)
function parseCsvLine(line) {
const result = [];
let current = '';
let inQuotes = false;
for (let i = 0; i < line.length; i++) {
const char = line[i];
if (char === '"') {
inQuotes = !inQuotes;
} else if (char === ',' && !inQuotes) {
result.push(current.trim());
current = '';
} else {
current += char;
}
}
result.push(current.trim());
return result;
}
// Check if this file is being run directly
if (import.meta.url === `file://${process.argv[1]}`) {
uploadVisitsData()
.then(() => {
console.log('Upload script completed successfully');
process.exit(0);
})
.catch((error) => {
console.error('Upload script failed:', error);
process.exit(1);
});
}
export { uploadVisitsData };