after a fair bit of changes, it is now working
diff --git a/build/schemabuilder.js b/build/schemabuilder.js
index e7589bb..20722ec 100644
--- a/build/schemabuilder.js
+++ b/build/schemabuilder.js
@@ -7,13 +7,19 @@ const relativePath = f => path.resolve(__dirname, "..", f);
 
 const tsconfig = relativePath("tsconfig.json");
 
-for(let {input, output, type} of schemas) {
+for (let { input, output, type } of schemas) {
+    console.log("Generating schema for:", { input, output, type });
     const config = {
         path: relativePath(input),
         tsconfig,
         type
     };
-    const schema = tsj.createGenerator(config).createSchema(config.type);
-    const schemaString = JSON.stringify(schema, null, 2);
-    fs.writeFileSync(relativePath(output), schemaString);
+    try {
+        const schema = tsj.createGenerator(config).createSchema(config.type);
+        const schemaString = JSON.stringify(schema, null, 2);
+        console.log(`Writing schema to ${relativePath(output)}`);
+        fs.writeFileSync(relativePath(output), schemaString);
+    } catch (error) {
+        console.error(`Error generating schema for ${type}:`, error);
+    }
 }
diff --git a/etc/firestore.rules b/etc/firestore.rules
index abd5a65..e5675e7 100644
--- a/etc/firestore.rules
+++ b/etc/firestore.rules
@@ -13,10 +13,12 @@ service cloud.firestore {
         function hasAccessByRole() {
           // don't allow access to personal bags in this match clause
           let isPersonalBag = bagName.matches('^user%3A.*');
-          // anybody with at least reader can read non-personal bags
-          let allowedByRole = get(/databases/$(database)/documents/wikis/$(wikiName)/users/$(request.auth.uid)).data.role >= 2;
+          // Verify role exists and is valid
+          let allowedByRole = exists(/databases/$(database)/documents/wikis/$(wikiName)/users/$(request.auth.uid)) && 
+                              get(/databases/$(database)/documents/wikis/$(wikiName)/users/$(request.auth.uid)).data.role >= 2;
           return !isPersonalBag && allowedByRole;
         }
+
         allow get, list: if request.auth != null && hasAccessByRole();
     }
   }
diff --git a/firebase.production.json b/firebase.production.json
index 9758800..2eaa7b1 100644
--- a/firebase.production.json
+++ b/firebase.production.json
@@ -7,7 +7,7 @@
   },
   "hosting": [
     {
-      "site": "pn-wiki",
+      "site": "kronako-wiki",
       "public": "public",
       "redirects": [{
           "source": "/static/:file*",
diff --git a/package.json b/package.json
index ac5c55f..b1c1e93 100644
--- a/package.json
+++ b/package.json
@@ -58,11 +58,15 @@
     "yargs": "^16.2.0"
   },
   "dependencies": {
+    "@js-sdsl/ordered-map": "^4.4.2",
+    "@types/helmet": "^0.0.48",
     "ajv": "^7.2.1",
     "cors": "^2.8.5",
     "express": "^4.17.1",
+    "express-rate-limit": "^7.5.0",
     "firebase-admin": "^9.5.0",
     "firebase-functions": "^3.13.2",
+    "helmet": "^8.0.0",
     "inversify": "^5.0.5",
     "reflect-metadata": "^0.1.13",
     "source-map-support": "^0.5.19"
     
diff --git a/src/backend/api/endpoints.ts b/src/backend/api/endpoints.ts
index 9a5d608..4540f34 100644
--- a/src/backend/api/endpoints.ts
+++ b/src/backend/api/endpoints.ts
@@ -20,7 +20,7 @@
  */
 
 import cors from 'cors';
-import * as express from 'express';
+import express from 'express';
 import { inject, injectable } from 'inversify';
 import { TW5FirebaseError, TW5FirebaseErrorCode } from '../../shared/model/errors';
 import { SingleWikiNamespacedTiddler } from '../../shared/model/store';
@@ -160,18 +160,61 @@ export class APIEndpointFactory {
     }
 
     createAPI() {
-        const api = express.default();
-        api.use(cors({ origin: true }));
+        const api = express();
+        
+        // CORS middleware
+        api.use(cors({ 
+            origin: 'https://kronako-wiki.web.app', 
+            methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
+            allowedHeaders: 'Authorization, Content-Type, Accept',
+            optionsSuccessStatus: 204 
+        }));
+        
+        // Preflight request handling
+        api.options('*', (req, res) => {
+            res.set({
+                'Access-Control-Allow-Origin': 'https://kronako-wiki.web.app',
+                'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
+                'Access-Control-Allow-Headers': 'Authorization, Content-Type, Accept',
+            });
+            res.status(204).send(); // Respond with no content
+        });
+    
+        // Add CORS headers to all responses
+        api.use((req, res, next) => {
+            res.set('Access-Control-Allow-Origin', 'https://kronako-wiki.web.app');
+            next();
+        });
+    
+        // Authorization header validation
+        api.use((req, res, next) => {
+            if (req.headers.authorization) {
+                next(); // Authorization logic passes
+            } else {
+                res.status(401).send("Authorization header is required");
+            }
+        });
+    
+        // Attach middleware
         api.use(this.authenticatorMiddleware.authenticate.bind(this.authenticatorMiddleware));
+    
+        // Bind endpoints
         const read = this.bindAndSerialize(this.read);
         const write = this.bindAndSerialize(this.write);
         api.get('/:wiki/recipes/:recipe/tiddlers/:title?', read);
         api.get('/:wiki/bags/:bag/tiddlers/:title?', read);
-        api.put('/:wiki/recipes/:recipe/tiddlers/:title', write); // create
-        api.put('/:wiki/recipes/:recipe/tiddlers/:title/revisions/:revision', write); // update
-        api.put('/:wiki/bags/:bag/tiddlers/:title', write); // create
-        api.put('/:wiki/bags/:bag/tiddlers/:title/revisions/:revision', write); // update
+        api.put('/:wiki/recipes/:recipe/tiddlers/:title', write);
+        api.put('/:wiki/recipes/:recipe/tiddlers/:title/revisions/:revision', write);
+        api.put('/:wiki/bags/:bag/tiddlers/:title', write);
+        api.put('/:wiki/bags/:bag/tiddlers/:title/revisions/:revision', write);
         api.delete('/:wiki/bags/:bag/tiddlers/:title/revisions/:revision', this.bindAndSerialize(this.remove));
+    
+        // Error handling middleware
+        api.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
+            console.error(err.stack);
+            res.status(err.status || 500).send(err.message || 'Internal Server Error');
+        });
+    
         return api;
     }
 }
diff --git a/src/backend/api/policy-checker.ts b/src/backend/api/policy-checker.ts
index 1d6121b..6d09ada 100644
--- a/src/backend/api/policy-checker.ts
+++ b/src/backend/api/policy-checker.ts
@@ -105,7 +105,7 @@ export class PolicyChecker {
         return {
             ...bagPermission,
             allowed,
-            reason: allowed ? undefined : PolicyRejectReason.CONTRAINTS,
+            reason: allowed ? undefined : PolicyRejectReason.CONSTRAINTS,
         };
     }
 
diff --git a/src/backend/index.ts b/src/backend/index.ts
index c695660..1bf9b61 100644
--- a/src/backend/index.ts
+++ b/src/backend/index.ts
@@ -2,16 +2,49 @@
 import 'reflect-metadata';
 import 'source-map-support/register';
 import * as functions from 'firebase-functions';
+import cors from 'cors';
+import express, { RequestHandler } from 'express';
 import { productionStartup } from './common/startup';
 import { Component } from './common/ioc/components';
 import { Config } from '../shared/model/config';
 import { APIEndpointFactory } from './api/endpoints';
 
+// Initialize the IoC container and components
 const container = productionStartup();
 const apiEndpointFactory = container.get<APIEndpointFactory>(Component.APIEndpointFactory);
+const config = container.get<Config>(Component.config);
 
+// Create an Express app and apply middleware
+const app = express();
+
+// Define CORS options
+const corsOptions = {
+  origin: 'https://kronako-wiki.web.app', // Replace with your allowed origin
+  methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
+  allowedHeaders: 'Authorization, Content-Type, X-Requested-With, Accept',
+  optionsSuccessStatus: 204,
+};
+
+
+// Apply CORS middleware with explicit type casting
+const corsMiddleware = cors(corsOptions) as RequestHandler;
+app.use(corsMiddleware);
+app.options('*', corsMiddleware);
+
+// Attach the API endpoints to the Express app
+app.use('/api', apiEndpointFactory.createAPI());
+
+// Add a logging middleware for debugging
+app.use((req: express.Request, res: express.Response, next: express.NextFunction) => {
+  console.log(`[${req.method}] ${req.url}`);
+  console.log(`Headers:`, req.headers);
+  next();
+});
+
+// Export the Firebase Function
 export const wiki = functions
-    .region(container.get<Config>(Component.config).deploy.apiRegion)
-    .runWith({
-      timeoutSeconds: 540
-    }).https.onRequest(apiEndpointFactory.createAPI());
+  .region(config.deploy.apiRegion)
+  .runWith({
+    timeoutSeconds: 540,
+  })
+  .https.onRequest(app);
diff --git a/src/shared/model/bag-policy.ts b/src/shared/model/bag-policy.ts
index c4fe154..fdd610e 100644
--- a/src/shared/model/bag-policy.ts
+++ b/src/shared/model/bag-policy.ts
@@ -8,7 +8,7 @@ export type BagPolicy = { [key in AccessType]: Grantee[] } & { constraints?: str
 
 export enum PolicyRejectReason {
     INSUFFICIENT_PERMISSION = 'insufficient_permissions',
-    CONTRAINTS = 'constraints',
+    CONSTRAINTS = 'constraints',
 }
 
 export const standardPolicies: { [bag: string]: BagPolicy } = {
diff --git a/tsconfig.json b/tsconfig.json
index 4065bab..11aec7d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -23,6 +23,7 @@
     "typeRoots": ["node_modules/@types"],
     "noUnusedLocals": true,
     "noImplicitReturns": true,
+    "allowSyntheticDefaultImports": true,
     "noFallthroughCasesInSwitch": true
   },
   "include": ["src", "generated"],
and had to update the config.production.json to         "apiEndpoint": "https://us-central1-kronako-wiki.cloudfunctions.net/wiki/api/"