Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ pm-ops-map/
├── render.yaml One-click Render deploy for the sync server
├── .github/workflows/ci.yml CI: install, test, audit, build (app + sync server as separate jobs)
├── CONTRIBUTING.md
├── SECURITY.md
├── LICENSE.txt
└── webpack.config.*.js Optional build configs (not needed to run)
```
Expand Down Expand Up @@ -474,6 +475,8 @@ If you're evaluating this for real use today: the core ownership/maintenance/por

See [CONTRIBUTING.md](CONTRIBUTING.md). PRs welcome — especially department templates, mobile UX improvements, and visualization options.

Found a security issue? See [SECURITY.md](SECURITY.md) — please don't open a public issue for it.

---

## License
Expand Down
36 changes: 36 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Security Policy

## Reporting a vulnerability

Please use GitHub's [private vulnerability reporting](security/advisories/new)
for this repository rather than opening a public issue. If that's not
available, open an issue that describes the problem in general terms without
a working exploit, and a maintainer will follow up to get details privately.

There's no bug bounty — this is a free, open-source hobby project — but
reports are genuinely appreciated and will be credited in the fix unless you
ask otherwise.

## Security model

**Main app.** PM Ops Map is a zero-backend, client-only app: it runs entirely
in your browser and stores its data in `localStorage` on your device. There is
no server, no account system, and no PM Ops Map–operated service that sees
your data. The main risks are the ones inherent to any browser-storage app:
anyone with access to the browser profile can read the stored data, and it is
only as safe as the device it runs on.

**Optional sync server** (`server/`). Teams that opt into Team Sync run their
own self-hosted instance to share one workspace across devices. Its security
model is intentionally lightweight — workspace passphrases are hashed with
`scrypt` server-side, but the client keeps its own copy in `localStorage`
unencrypted, there's no per-device access revocation, and it's designed for a
small team that already trusts each other rather than for adversarial
multi-tenant use. Full details are in
[`server/README.md`](server/README.md#security-model-honestly). If you deploy
it, always run it behind HTTPS.

## Supported versions

This project doesn't yet follow a formal versioning/release cycle — the
`master` branch is the supported version. Fixes land there.
11 changes: 11 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@
<title>PM Ops Map</title>
<meta name="description" content="Map your property management company's tasks, ownership, and accountability across every department.">

<!-- TODO: replace https://your-deployment-url.vercel.app with the real deployed URL -->
<meta property="og:type" content="website">
<meta property="og:title" content="PM Ops Map — free, open-source property management ops tracker">
<meta property="og:description" content="Map your property management company's tasks, ownership, and accountability across every department. Zero backend, runs entirely in your browser.">
<meta property="og:image" content="https://your-deployment-url.vercel.app/og-image.png">
<meta property="og:url" content="https://your-deployment-url.vercel.app/">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="PM Ops Map — free, open-source property management ops tracker">
<meta name="twitter:description" content="Map your property management company's tasks, ownership, and accountability across every department. Zero backend, runs entirely in your browser.">
<meta name="twitter:image" content="https://your-deployment-url.vercel.app/og-image.png">

<link rel="stylesheet" href="css/style.css">

<link rel="icon" href="favicon.ico" sizes="any">
Expand Down
Binary file added og-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 10 additions & 1 deletion webpack.config.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,16 @@ class InlineConfigForFileProtocolPlugin {
'InlineConfigForFileProtocolPlugin',
(data, cb) => {
const configJson = fs.readFileSync(path.resolve(__dirname, 'config.json'), 'utf8');
const originalTag = '<script type="module" src="js/app.js"></script>';
if (!data.html.includes(originalTag)) {
return cb(new Error(
`InlineConfigForFileProtocolPlugin: expected to find ${originalTag} in the rendered ` +
'HTML but did not — index.html\'s script tag changed, so config.json would not be inlined ' +
'and the built app would silently fail to load config over file://.'
));
}
data.html = data.html.replace(
'<script type="module" src="js/app.js"></script>',
originalTag,
`<script>window.__PM_OPS_CONFIG__=${JSON.stringify(JSON.parse(configJson))};</script>\n<script src="js/app.js" defer></script>`
);
cb(null, data);
Expand All @@ -48,6 +56,7 @@ module.exports = merge(common, {
{ from: 'favicon.ico', to: 'favicon.ico' },
{ from: 'robots.txt', to: 'robots.txt' },
{ from: 'icon.png', to: 'icon.png' },
{ from: 'og-image.png', to: 'og-image.png' },
{ from: '404.html', to: '404.html' },
{ from: 'site.webmanifest', to: 'site.webmanifest' },
],
Expand Down
Loading