start docs
This commit is contained in:
111
docs/bib/main.bib
Normal file
111
docs/bib/main.bib
Normal file
@@ -0,0 +1,111 @@
|
||||
@online{svelte-docs,
|
||||
title = {Svelte Documentation},
|
||||
author = {{Svelte Core Team}},
|
||||
year = {2025},
|
||||
url = {https://svelte.dev/docs},
|
||||
note = {Geraadpleegd op 26 december 2025}
|
||||
}
|
||||
|
||||
@online{sveltekit-docs,
|
||||
title = {SvelteKit Documentation},
|
||||
author = {{Svelte Core Team}},
|
||||
year = {2025},
|
||||
url = {https://kit.svelte.dev/docs},
|
||||
note = {Geraadpleegd op 26 december 2025}
|
||||
}
|
||||
|
||||
@online{vite-docs,
|
||||
title = {Vite -- Next Generation Frontend Tooling},
|
||||
author = {Evan You and Vite Contributors},
|
||||
year = {2025},
|
||||
url = {https://vitejs.dev/},
|
||||
note = {Geraadpleegd op 26 december 2025}
|
||||
}
|
||||
|
||||
@online{maplibre-docs,
|
||||
title = {MapLibre GL JS Documentation},
|
||||
author = {{MapLibre Community}},
|
||||
year = {2025},
|
||||
url = {https://maplibre.org/maplibre-gl-js/docs/},
|
||||
note = {Geraadpleegd op 26 december 2025}
|
||||
}
|
||||
|
||||
@online{drizzle-docs,
|
||||
title = {Drizzle ORM Documentation},
|
||||
author = {{Drizzle Team}},
|
||||
year = {2025},
|
||||
url = {https://orm.drizzle.team/docs},
|
||||
note = {Geraadpleegd op 26 december 2025}
|
||||
}
|
||||
|
||||
@online{convex-docs,
|
||||
title = {Convex Documentation},
|
||||
author = {{Convex Team}},
|
||||
year = {2025},
|
||||
url = {https://convex.dev/docs},
|
||||
note = {Geraadpleegd op 26 december 2025}
|
||||
}
|
||||
|
||||
@online{lucia-docs,
|
||||
title = {Lucia Auth Documentation},
|
||||
author = {{Lucia Contributors}},
|
||||
year = {2025},
|
||||
url = {https://lucia-auth.com/},
|
||||
note = {Geraadpleegd op 26 december 2025}
|
||||
}
|
||||
|
||||
@online{cloudflare-r2-docs,
|
||||
title = {Cloudflare R2 Object Storage Documentation},
|
||||
author = {{Cloudflare, Inc.}},
|
||||
year = {2025},
|
||||
url = {https://developers.cloudflare.com/r2/},
|
||||
note = {Geraadpleegd op 26 december 2025}
|
||||
}
|
||||
|
||||
@online{web-push-spec,
|
||||
title = {The Web Push Protocol},
|
||||
author = {Barnes, Martin and Others},
|
||||
year = {2016},
|
||||
url = {https://datatracker.ietf.org/doc/html/rfc8030},
|
||||
note = {Geraadpleegd op 26 december 2025}
|
||||
}
|
||||
|
||||
@online{google-maps-platform,
|
||||
title = {Google Maps Platform Documentation},
|
||||
author = {{Google LLC}},
|
||||
year = {2025},
|
||||
url = {https://developers.google.com/maps/documentation},
|
||||
note = {Geraadpleegd op 26 december 2025}
|
||||
}
|
||||
|
||||
@online{shadcn-svelte,
|
||||
title = {shadcn-svelte: Re-usable Components},
|
||||
author = {Delaney, huntabyte and Contributors},
|
||||
year = {2025},
|
||||
url = {https://www.shadcn-svelte.com/},
|
||||
note = {Geraadpleegd op 26 december 2025}
|
||||
}
|
||||
|
||||
@online{mintlify-docs,
|
||||
title = {Mintlify Documentation Platform},
|
||||
author = {{Mintlify, Inc.}},
|
||||
year = {2025},
|
||||
url = {https://mintlify.com/},
|
||||
note = {Geraadpleegd op 26 december 2025}
|
||||
}
|
||||
|
||||
@online{docker-docs,
|
||||
title = {Docker Documentation},
|
||||
author = {{Docker, Inc.}},
|
||||
year = {2025},
|
||||
url = {https://docs.docker.com/},
|
||||
note = {Geraadpleegd op 26 december 2025}
|
||||
}
|
||||
|
||||
@online{hetzner-cloud,
|
||||
title = {Hetzner Cloud Documentation},
|
||||
author = {{Hetzner Online GmbH}},
|
||||
year = {2025},
|
||||
url = {https://docs.hetzner.com/cloud/},
|
||||
note = {Geraadpleegd op 26 december 2025}
|
||||
}
|
||||
724
docs/erd.svg
Normal file
724
docs/erd.svg
Normal file
@@ -0,0 +1,724 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.47.0 (20210316.0004)
|
||||
-->
|
||||
<!-- Title: dbml Pages: 1 -->
|
||||
<svg width="3268pt" height="5203pt"
|
||||
viewBox="0.00 0.00 3268.28 5203.18" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 5199.18)">
|
||||
<title>dbml</title>
|
||||
<!-- find -->
|
||||
<g id="find" class="node">
|
||||
<title>find</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1353.34" cy="-4090.37" rx="439.23" ry="511.89"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="1045.34,-4390.37 1045.34,-4450.37 1662.34,-4450.37 1662.34,-4390.37 1045.34,-4390.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1045.34,-4390.37 1045.34,-4450.37 1662.34,-4450.37 1662.34,-4390.37 1045.34,-4390.37"/>
|
||||
<text text-anchor="start" x="1265.8" y="-4411.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       find       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1045.34,-4330.37 1045.34,-4390.37 1662.34,-4390.37 1662.34,-4330.37 1045.34,-4330.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1045.34,-4330.37 1045.34,-4390.37 1662.34,-4390.37 1662.34,-4330.37 1045.34,-4330.37"/>
|
||||
<text text-anchor="start" x="1056.34" y="-4351.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="1081.23" y="-4351.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="1560.67" y="-4351.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="1612.25" y="-4351.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1621.14" y="-4351.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1045.34,-4270.37 1045.34,-4330.37 1662.34,-4330.37 1662.34,-4270.37 1045.34,-4270.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1045.34,-4270.37 1045.34,-4330.37 1662.34,-4330.37 1662.34,-4270.37 1045.34,-4270.37"/>
|
||||
<text text-anchor="start" x="1056.34" y="-4290.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">location_id    </text>
|
||||
<text text-anchor="start" x="1560.67" y="-4291.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="1612.25" y="-4291.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1621.14" y="-4291.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1045.34,-4210.37 1045.34,-4270.37 1662.34,-4270.37 1662.34,-4210.37 1045.34,-4210.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1045.34,-4210.37 1045.34,-4270.37 1662.34,-4270.37 1662.34,-4210.37 1045.34,-4210.37"/>
|
||||
<text text-anchor="start" x="1056.34" y="-4230.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">user_id    </text>
|
||||
<text text-anchor="start" x="1560.67" y="-4231.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="1612.25" y="-4231.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1621.14" y="-4231.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1045.34,-4150.37 1045.34,-4210.37 1662.34,-4210.37 1662.34,-4150.37 1045.34,-4150.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1045.34,-4150.37 1045.34,-4210.37 1662.34,-4210.37 1662.34,-4150.37 1045.34,-4150.37"/>
|
||||
<text text-anchor="start" x="1056.34" y="-4170.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">title    </text>
|
||||
<text text-anchor="start" x="1560.67" y="-4171.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="1612.25" y="-4171.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1621.14" y="-4171.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1045.34,-4090.37 1045.34,-4150.37 1662.34,-4150.37 1662.34,-4090.37 1045.34,-4090.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1045.34,-4090.37 1045.34,-4150.37 1662.34,-4150.37 1662.34,-4090.37 1045.34,-4090.37"/>
|
||||
<text text-anchor="start" x="1056.34" y="-4110.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">description    </text>
|
||||
<text text-anchor="start" x="1599.77" y="-4111.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1045.34,-4030.37 1045.34,-4090.37 1662.34,-4090.37 1662.34,-4030.37 1045.34,-4030.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1045.34,-4030.37 1045.34,-4090.37 1662.34,-4090.37 1662.34,-4030.37 1045.34,-4030.37"/>
|
||||
<text text-anchor="start" x="1056.34" y="-4050.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">category    </text>
|
||||
<text text-anchor="start" x="1599.77" y="-4051.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1045.34,-3970.37 1045.34,-4030.37 1662.34,-4030.37 1662.34,-3970.37 1045.34,-3970.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1045.34,-3970.37 1045.34,-4030.37 1662.34,-4030.37 1662.34,-3970.37 1045.34,-3970.37"/>
|
||||
<text text-anchor="start" x="1056.34" y="-3990.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">rating    </text>
|
||||
<text text-anchor="start" x="1553.54" y="-3991.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">integer</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1045.34,-3910.37 1045.34,-3970.37 1662.34,-3970.37 1662.34,-3910.37 1045.34,-3910.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1045.34,-3910.37 1045.34,-3970.37 1662.34,-3970.37 1662.34,-3910.37 1045.34,-3910.37"/>
|
||||
<text text-anchor="start" x="1056.34" y="-3930.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">rating_count    </text>
|
||||
<text text-anchor="start" x="1553.54" y="-3931.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">integer</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1045.34,-3850.37 1045.34,-3910.37 1662.34,-3910.37 1662.34,-3850.37 1045.34,-3850.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1045.34,-3850.37 1045.34,-3910.37 1662.34,-3910.37 1662.34,-3850.37 1045.34,-3850.37"/>
|
||||
<text text-anchor="start" x="1056.34" y="-3870.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">is_public    </text>
|
||||
<text text-anchor="start" x="1553.54" y="-3871.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">integer</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1045.34,-3790.37 1045.34,-3850.37 1662.34,-3850.37 1662.34,-3790.37 1045.34,-3790.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1045.34,-3790.37 1045.34,-3850.37 1662.34,-3850.37 1662.34,-3790.37 1045.34,-3790.37"/>
|
||||
<text text-anchor="start" x="1056.34" y="-3810.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">created_at    </text>
|
||||
<text text-anchor="start" x="1251.33" y="-3811.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="1612.25" y="-3811.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1621.14" y="-3811.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1045.34,-3730.37 1045.34,-3790.37 1662.34,-3790.37 1662.34,-3730.37 1045.34,-3730.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1045.34,-3730.37 1045.34,-3790.37 1662.34,-3790.37 1662.34,-3730.37 1045.34,-3730.37"/>
|
||||
<text text-anchor="start" x="1056.01" y="-3750.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">updated_at    </text>
|
||||
<text text-anchor="start" x="1251.33" y="-3751.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="1612.26" y="-3751.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1621.15" y="-3751.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1043.84,-3729.37 1043.84,-4451.37 1662.84,-4451.37 1662.84,-3729.37 1043.84,-3729.37"/>
|
||||
</g>
|
||||
<!-- location -->
|
||||
<g id="location" class="node">
|
||||
<title>location</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="2267.57" cy="-3966.37" rx="433" ry="384.83"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="1963.57,-4176.37 1963.57,-4236.37 2571.57,-4236.37 2571.57,-4176.37 1963.57,-4176.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-4176.37 1963.57,-4236.37 2571.57,-4236.37 2571.57,-4176.37 1963.57,-4176.37"/>
|
||||
<text text-anchor="start" x="2150.19" y="-4197.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       location       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-4116.37 1963.57,-4176.37 2571.57,-4176.37 2571.57,-4116.37 1963.57,-4116.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-4116.37 1963.57,-4176.37 2571.57,-4176.37 2571.57,-4116.37 1963.57,-4116.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-4137.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="1999.46" y="-4137.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="2469.9" y="-4137.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2521.48" y="-4137.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-4137.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-4056.37 1963.57,-4116.37 2571.57,-4116.37 2571.57,-4056.37 1963.57,-4056.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-4056.37 1963.57,-4116.37 2571.57,-4116.37 2571.57,-4056.37 1963.57,-4056.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-4076.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">user_id    </text>
|
||||
<text text-anchor="start" x="2469.9" y="-4077.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2521.48" y="-4077.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-4077.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-3996.37 1963.57,-4056.37 2571.57,-4056.37 2571.57,-3996.37 1963.57,-3996.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-3996.37 1963.57,-4056.37 2571.57,-4056.37 2571.57,-3996.37 1963.57,-3996.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-4016.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">latitude    </text>
|
||||
<text text-anchor="start" x="2469.9" y="-4017.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2521.48" y="-4017.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-4017.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-3936.37 1963.57,-3996.37 2571.57,-3996.37 2571.57,-3936.37 1963.57,-3936.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-3936.37 1963.57,-3996.37 2571.57,-3996.37 2571.57,-3936.37 1963.57,-3936.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-3956.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">longitude    </text>
|
||||
<text text-anchor="start" x="2469.9" y="-3957.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2521.48" y="-3957.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-3957.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-3876.37 1963.57,-3936.37 2571.57,-3936.37 2571.57,-3876.37 1963.57,-3876.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-3876.37 1963.57,-3936.37 2571.57,-3936.37 2571.57,-3876.37 1963.57,-3876.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-3896.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">location_name    </text>
|
||||
<text text-anchor="start" x="2508.99" y="-3897.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-3816.37 1963.57,-3876.37 2571.57,-3876.37 2571.57,-3816.37 1963.57,-3816.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-3816.37 1963.57,-3876.37 2571.57,-3876.37 2571.57,-3816.37 1963.57,-3816.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-3836.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">average_rating    </text>
|
||||
<text text-anchor="start" x="2462.76" y="-3837.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">integer</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-3756.37 1963.57,-3816.37 2571.57,-3816.37 2571.57,-3756.37 1963.57,-3756.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-3756.37 1963.57,-3816.37 2571.57,-3816.37 2571.57,-3756.37 1963.57,-3756.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-3776.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">rating_count    </text>
|
||||
<text text-anchor="start" x="2462.76" y="-3777.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">integer</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-3696.37 1963.57,-3756.37 2571.57,-3756.37 2571.57,-3696.37 1963.57,-3696.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-3696.37 1963.57,-3756.37 2571.57,-3756.37 2571.57,-3696.37 1963.57,-3696.37"/>
|
||||
<text text-anchor="start" x="1974.2" y="-3716.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">created_at    </text>
|
||||
<text text-anchor="start" x="2160.56" y="-3717.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="2521.48" y="-3717.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-3717.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1962.57,-3695.37 1962.57,-4237.37 2572.57,-4237.37 2572.57,-3695.37 1962.57,-3695.37"/>
|
||||
</g>
|
||||
<!-- find->location -->
|
||||
<!-- find->location -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>find:e->location:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M1663.34,-4300.37C1809.4,-4300.37 1812.91,-4153.5 1952.29,-4146.62"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="1952.65,-4150.11 1962.57,-4146.37 1952.48,-4143.11 1952.65,-4150.11"/>
|
||||
<text text-anchor="middle" x="1953.67" y="-4155.97" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="1669.56" y="-4309.97" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- user -->
|
||||
<g id="user" class="node">
|
||||
<title>user</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="3001.48" cy="-3159.37" rx="258.6" ry="299.63"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="2820.48,-3309.37 2820.48,-3369.37 3182.48,-3369.37 3182.48,-3309.37 2820.48,-3309.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="2820.48,-3309.37 2820.48,-3369.37 3182.48,-3369.37 3182.48,-3309.37 2820.48,-3309.37"/>
|
||||
<text text-anchor="start" x="2908.12" y="-3330.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       user       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="2820.48,-3249.37 2820.48,-3309.37 3182.48,-3309.37 3182.48,-3249.37 2820.48,-3249.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="2820.48,-3249.37 2820.48,-3309.37 3182.48,-3309.37 3182.48,-3249.37 2820.48,-3249.37"/>
|
||||
<text text-anchor="start" x="2831.48" y="-3270.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="2856.37" y="-3270.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="3080.82" y="-3270.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="3132.39" y="-3270.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="3141.28" y="-3270.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="2820.48,-3189.37 2820.48,-3249.37 3182.48,-3249.37 3182.48,-3189.37 2820.48,-3189.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="2820.48,-3189.37 2820.48,-3249.37 3182.48,-3249.37 3182.48,-3189.37 2820.48,-3189.37"/>
|
||||
<text text-anchor="start" x="2831.48" y="-3209.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">age    </text>
|
||||
<text text-anchor="start" x="3073.68" y="-3210.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">integer</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="2820.48,-3129.37 2820.48,-3189.37 3182.48,-3189.37 3182.48,-3129.37 2820.48,-3129.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="2820.48,-3129.37 2820.48,-3189.37 3182.48,-3189.37 3182.48,-3129.37 2820.48,-3129.37"/>
|
||||
<text text-anchor="start" x="2831.48" y="-3149.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">username    </text>
|
||||
<text text-anchor="start" x="3080.82" y="-3150.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="3132.39" y="-3150.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="3141.28" y="-3150.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="2820.48,-3069.37 2820.48,-3129.37 3182.48,-3129.37 3182.48,-3069.37 2820.48,-3069.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="2820.48,-3069.37 2820.48,-3129.37 3182.48,-3129.37 3182.48,-3069.37 2820.48,-3069.37"/>
|
||||
<text text-anchor="start" x="2831.48" y="-3089.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">password_hash    </text>
|
||||
<text text-anchor="start" x="3119.91" y="-3090.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="2820.48,-3009.37 2820.48,-3069.37 3182.48,-3069.37 3182.48,-3009.37 2820.48,-3009.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="2820.48,-3009.37 2820.48,-3069.37 3182.48,-3069.37 3182.48,-3009.37 2820.48,-3009.37"/>
|
||||
<text text-anchor="start" x="2831.48" y="-3029.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">google_id    </text>
|
||||
<text text-anchor="start" x="3119.91" y="-3030.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="2820.48,-2949.37 2820.48,-3009.37 3182.48,-3009.37 3182.48,-2949.37 2820.48,-2949.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="2820.48,-2949.37 2820.48,-3009.37 3182.48,-3009.37 3182.48,-2949.37 2820.48,-2949.37"/>
|
||||
<text text-anchor="start" x="2831.07" y="-2969.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">profile_picture_url    </text>
|
||||
<text text-anchor="start" x="3120.19" y="-2970.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="2819.48,-2948.37 2819.48,-3370.37 3183.48,-3370.37 3183.48,-2948.37 2819.48,-2948.37"/>
|
||||
</g>
|
||||
<!-- find->user -->
|
||||
<!-- find->user -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>find:e->user:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M1663.34,-4240.37C1890.69,-4240.37 1664.48,-308.85 1828.45,-151.37 1863.64,-117.57 2671.56,-117.5 2706.68,-151.37 2829.39,-269.73 2652.75,-3163 2809.7,-3275.97"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="2808.89,-3279.39 2819.48,-3279.37 2811.18,-3272.78 2808.89,-3279.39"/>
|
||||
<text text-anchor="middle" x="2828.38" y="-3250.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="1669.56" y="-4249.97" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- find_comment -->
|
||||
<g id="find_comment" class="node">
|
||||
<title>find_comment</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="439.11" cy="-4895.37" rx="439.23" ry="299.63"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="131.11,-5045.37 131.11,-5105.37 748.11,-5105.37 748.11,-5045.37 131.11,-5045.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="131.11,-5045.37 131.11,-5105.37 748.11,-5105.37 748.11,-5045.37 131.11,-5045.37"/>
|
||||
<text text-anchor="start" x="276.9" y="-5066.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       find_comment       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="131.11,-4985.37 131.11,-5045.37 748.11,-5045.37 748.11,-4985.37 131.11,-4985.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="131.11,-4985.37 131.11,-5045.37 748.11,-5045.37 748.11,-4985.37 131.11,-4985.37"/>
|
||||
<text text-anchor="start" x="142.11" y="-5006.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="167" y="-5006.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="646.45" y="-5006.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="698.02" y="-5006.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="706.91" y="-5006.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="131.11,-4925.37 131.11,-4985.37 748.11,-4985.37 748.11,-4925.37 131.11,-4925.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="131.11,-4925.37 131.11,-4985.37 748.11,-4985.37 748.11,-4925.37 131.11,-4925.37"/>
|
||||
<text text-anchor="start" x="142.11" y="-4945.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">find_id    </text>
|
||||
<text text-anchor="start" x="646.45" y="-4946.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="698.02" y="-4946.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="706.91" y="-4946.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="131.11,-4865.37 131.11,-4925.37 748.11,-4925.37 748.11,-4865.37 131.11,-4865.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="131.11,-4865.37 131.11,-4925.37 748.11,-4925.37 748.11,-4865.37 131.11,-4865.37"/>
|
||||
<text text-anchor="start" x="142.11" y="-4885.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">user_id    </text>
|
||||
<text text-anchor="start" x="646.45" y="-4886.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="698.02" y="-4886.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="706.91" y="-4886.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="131.11,-4805.37 131.11,-4865.37 748.11,-4865.37 748.11,-4805.37 131.11,-4805.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="131.11,-4805.37 131.11,-4865.37 748.11,-4865.37 748.11,-4805.37 131.11,-4805.37"/>
|
||||
<text text-anchor="start" x="142.11" y="-4825.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">content    </text>
|
||||
<text text-anchor="start" x="646.45" y="-4826.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="698.02" y="-4826.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="706.91" y="-4826.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="131.11,-4745.37 131.11,-4805.37 748.11,-4805.37 748.11,-4745.37 131.11,-4745.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="131.11,-4745.37 131.11,-4805.37 748.11,-4805.37 748.11,-4745.37 131.11,-4745.37"/>
|
||||
<text text-anchor="start" x="142.11" y="-4765.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">created_at    </text>
|
||||
<text text-anchor="start" x="337.1" y="-4766.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="698.02" y="-4766.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="706.91" y="-4766.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="131.11,-4685.37 131.11,-4745.37 748.11,-4745.37 748.11,-4685.37 131.11,-4685.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="131.11,-4685.37 131.11,-4745.37 748.11,-4745.37 748.11,-4685.37 131.11,-4685.37"/>
|
||||
<text text-anchor="start" x="141.78" y="-4705.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">updated_at    </text>
|
||||
<text text-anchor="start" x="337.11" y="-4706.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="698.03" y="-4706.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="706.92" y="-4706.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="129.61,-4684.37 129.61,-5106.37 748.61,-5106.37 748.61,-4684.37 129.61,-4684.37"/>
|
||||
</g>
|
||||
<!-- find_comment->find -->
|
||||
<!-- find_comment->find -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>find_comment:e->find:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M749.11,-4955.37C1040.86,-4955.37 755.97,-4374.23 1034.2,-4360.61"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="1034.43,-4364.11 1044.34,-4360.37 1034.26,-4357.11 1034.43,-4364.11"/>
|
||||
<text text-anchor="middle" x="1053.23" y="-4369.97" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="742.89" y="-4964.97" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- find_comment->user -->
|
||||
<!-- find_comment->user -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>find_comment:e->user:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M749.11,-4895.37C1229.69,-4895.37 1460.73,-4959.1 1792.45,-4611.37 1843.36,-4558 1773.32,-4498.37 1828.45,-4449.37 1975.08,-4319.06 2567.77,-4498.87 2706.68,-4360.37 2875.21,-4192.34 2586.64,-3305.88 2809.21,-3279.95"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="2809.69,-3283.43 2819.48,-3279.37 2809.3,-3276.44 2809.69,-3283.43"/>
|
||||
<text text-anchor="middle" x="2828.38" y="-3288.97" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="742.89" y="-4904.97" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- find_like -->
|
||||
<g id="find_like" class="node">
|
||||
<title>find_like</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="439.11" cy="-2872.37" rx="433" ry="214.92"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="135.11,-2962.37 135.11,-3022.37 743.11,-3022.37 743.11,-2962.37 135.11,-2962.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="135.11,-2962.37 135.11,-3022.37 743.11,-3022.37 743.11,-2962.37 135.11,-2962.37"/>
|
||||
<text text-anchor="start" x="318.19" y="-2983.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       find_like       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="135.11,-2902.37 135.11,-2962.37 743.11,-2962.37 743.11,-2902.37 135.11,-2902.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="135.11,-2902.37 135.11,-2962.37 743.11,-2962.37 743.11,-2902.37 135.11,-2902.37"/>
|
||||
<text text-anchor="start" x="146.11" y="-2923.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="171" y="-2923.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="641.45" y="-2923.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="693.02" y="-2923.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="701.91" y="-2923.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="135.11,-2842.37 135.11,-2902.37 743.11,-2902.37 743.11,-2842.37 135.11,-2842.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="135.11,-2842.37 135.11,-2902.37 743.11,-2902.37 743.11,-2842.37 135.11,-2842.37"/>
|
||||
<text text-anchor="start" x="146.11" y="-2862.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">find_id    </text>
|
||||
<text text-anchor="start" x="641.45" y="-2863.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="693.02" y="-2863.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="701.91" y="-2863.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="135.11,-2782.37 135.11,-2842.37 743.11,-2842.37 743.11,-2782.37 135.11,-2782.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="135.11,-2782.37 135.11,-2842.37 743.11,-2842.37 743.11,-2782.37 135.11,-2782.37"/>
|
||||
<text text-anchor="start" x="146.11" y="-2802.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">user_id    </text>
|
||||
<text text-anchor="start" x="641.45" y="-2803.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="693.02" y="-2803.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="701.91" y="-2803.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="135.11,-2722.37 135.11,-2782.37 743.11,-2782.37 743.11,-2722.37 135.11,-2722.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="135.11,-2722.37 135.11,-2782.37 743.11,-2782.37 743.11,-2722.37 135.11,-2722.37"/>
|
||||
<text text-anchor="start" x="145.74" y="-2742.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">created_at    </text>
|
||||
<text text-anchor="start" x="332.11" y="-2743.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="693.03" y="-2743.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="701.92" y="-2743.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="134.11,-2721.37 134.11,-3023.37 744.11,-3023.37 744.11,-2721.37 134.11,-2721.37"/>
|
||||
</g>
|
||||
<!-- find_like->find -->
|
||||
<!-- find_like->find -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>find_like:e->find:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M744.11,-2872.37C1077.98,-2872.37 714.61,-4330.01 1034.19,-4359.9"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="1034.19,-4363.41 1044.34,-4360.37 1034.51,-4356.41 1034.19,-4363.41"/>
|
||||
<text text-anchor="middle" x="1053.23" y="-4331.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="737.89" y="-2843.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- find_like->user -->
|
||||
<!-- find_like->user -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>find_like:e->user:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M744.11,-2812.37C1039.61,-2812.37 708.53,-370.52 914.23,-158.37 1053.03,-15.22 2563.23,67.13 2706.68,-71.37 2832.6,-192.94 2648.23,-3165.94 2809.93,-3276.22"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="2808.89,-3279.56 2819.48,-3279.37 2811.08,-3272.91 2808.89,-3279.56"/>
|
||||
<text text-anchor="middle" x="2810.59" y="-3250.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="737.89" y="-2783.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- find_media -->
|
||||
<g id="find_media" class="node">
|
||||
<title>find_media</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="439.11" cy="-4150.37" rx="433" ry="427.19"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="135.11,-4390.37 135.11,-4450.37 743.11,-4450.37 743.11,-4390.37 135.11,-4390.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="135.11,-4390.37 135.11,-4450.37 743.11,-4450.37 743.11,-4390.37 135.11,-4390.37"/>
|
||||
<text text-anchor="start" x="298.62" y="-4411.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       find_media       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="135.11,-4330.37 135.11,-4390.37 743.11,-4390.37 743.11,-4330.37 135.11,-4330.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="135.11,-4330.37 135.11,-4390.37 743.11,-4390.37 743.11,-4330.37 135.11,-4330.37"/>
|
||||
<text text-anchor="start" x="146.11" y="-4351.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="171" y="-4351.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="641.45" y="-4351.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="693.02" y="-4351.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="701.91" y="-4351.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="135.11,-4270.37 135.11,-4330.37 743.11,-4330.37 743.11,-4270.37 135.11,-4270.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="135.11,-4270.37 135.11,-4330.37 743.11,-4330.37 743.11,-4270.37 135.11,-4270.37"/>
|
||||
<text text-anchor="start" x="146.11" y="-4290.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">find_id    </text>
|
||||
<text text-anchor="start" x="641.45" y="-4291.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="693.02" y="-4291.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="701.91" y="-4291.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="135.11,-4210.37 135.11,-4270.37 743.11,-4270.37 743.11,-4210.37 135.11,-4210.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="135.11,-4210.37 135.11,-4270.37 743.11,-4270.37 743.11,-4210.37 135.11,-4210.37"/>
|
||||
<text text-anchor="start" x="146.11" y="-4230.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">type    </text>
|
||||
<text text-anchor="start" x="641.45" y="-4231.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="693.02" y="-4231.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="701.91" y="-4231.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="135.11,-4150.37 135.11,-4210.37 743.11,-4210.37 743.11,-4150.37 135.11,-4150.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="135.11,-4150.37 135.11,-4210.37 743.11,-4210.37 743.11,-4150.37 135.11,-4150.37"/>
|
||||
<text text-anchor="start" x="146.11" y="-4170.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">url    </text>
|
||||
<text text-anchor="start" x="641.45" y="-4171.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="693.02" y="-4171.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="701.91" y="-4171.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="135.11,-4090.37 135.11,-4150.37 743.11,-4150.37 743.11,-4090.37 135.11,-4090.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="135.11,-4090.37 135.11,-4150.37 743.11,-4150.37 743.11,-4090.37 135.11,-4090.37"/>
|
||||
<text text-anchor="start" x="146.11" y="-4110.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">thumbnail_url    </text>
|
||||
<text text-anchor="start" x="680.54" y="-4111.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="135.11,-4030.37 135.11,-4090.37 743.11,-4090.37 743.11,-4030.37 135.11,-4030.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="135.11,-4030.37 135.11,-4090.37 743.11,-4090.37 743.11,-4030.37 135.11,-4030.37"/>
|
||||
<text text-anchor="start" x="146.11" y="-4050.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">fallback_url    </text>
|
||||
<text text-anchor="start" x="680.54" y="-4051.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="135.11,-3970.37 135.11,-4030.37 743.11,-4030.37 743.11,-3970.37 135.11,-3970.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="135.11,-3970.37 135.11,-4030.37 743.11,-4030.37 743.11,-3970.37 135.11,-3970.37"/>
|
||||
<text text-anchor="start" x="146.11" y="-3990.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">fallback_thumbnail_url    </text>
|
||||
<text text-anchor="start" x="680.54" y="-3991.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="135.11,-3910.37 135.11,-3970.37 743.11,-3970.37 743.11,-3910.37 135.11,-3910.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="135.11,-3910.37 135.11,-3970.37 743.11,-3970.37 743.11,-3910.37 135.11,-3910.37"/>
|
||||
<text text-anchor="start" x="146.11" y="-3930.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">order_index    </text>
|
||||
<text text-anchor="start" x="634.31" y="-3931.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">integer</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="135.11,-3850.37 135.11,-3910.37 743.11,-3910.37 743.11,-3850.37 135.11,-3850.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="135.11,-3850.37 135.11,-3910.37 743.11,-3910.37 743.11,-3850.37 135.11,-3850.37"/>
|
||||
<text text-anchor="start" x="145.74" y="-3870.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">created_at    </text>
|
||||
<text text-anchor="start" x="332.11" y="-3871.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="693.03" y="-3871.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="701.92" y="-3871.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="134.11,-3849.37 134.11,-4451.37 744.11,-4451.37 744.11,-3849.37 134.11,-3849.37"/>
|
||||
</g>
|
||||
<!-- find_media->find -->
|
||||
<!-- find_media->find -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>find_media:e->find:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M744.11,-4300.37C876.73,-4300.37 906.77,-4357.36 1034.18,-4360.26"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="1034.3,-4363.76 1044.34,-4360.37 1034.38,-4356.76 1034.3,-4363.76"/>
|
||||
<text text-anchor="middle" x="1035.45" y="-4369.97" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="737.89" y="-4309.97" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- find_rating -->
|
||||
<g id="find_rating" class="node">
|
||||
<title>find_rating</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="439.11" cy="-3405.37" rx="439.23" ry="299.63"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="131.11,-3555.37 131.11,-3615.37 748.11,-3615.37 748.11,-3555.37 131.11,-3555.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="131.11,-3555.37 131.11,-3615.37 748.11,-3615.37 748.11,-3555.37 131.11,-3555.37"/>
|
||||
<text text-anchor="start" x="302.68" y="-3576.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       find_rating       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="131.11,-3495.37 131.11,-3555.37 748.11,-3555.37 748.11,-3495.37 131.11,-3495.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="131.11,-3495.37 131.11,-3555.37 748.11,-3555.37 748.11,-3495.37 131.11,-3495.37"/>
|
||||
<text text-anchor="start" x="142.11" y="-3516.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="167" y="-3516.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="646.45" y="-3516.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="698.02" y="-3516.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="706.91" y="-3516.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="131.11,-3435.37 131.11,-3495.37 748.11,-3495.37 748.11,-3435.37 131.11,-3435.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="131.11,-3435.37 131.11,-3495.37 748.11,-3495.37 748.11,-3435.37 131.11,-3435.37"/>
|
||||
<text text-anchor="start" x="142.11" y="-3455.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">find_id    </text>
|
||||
<text text-anchor="start" x="646.45" y="-3456.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="698.02" y="-3456.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="706.91" y="-3456.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="131.11,-3375.37 131.11,-3435.37 748.11,-3435.37 748.11,-3375.37 131.11,-3375.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="131.11,-3375.37 131.11,-3435.37 748.11,-3435.37 748.11,-3375.37 131.11,-3375.37"/>
|
||||
<text text-anchor="start" x="142.11" y="-3395.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">user_id    </text>
|
||||
<text text-anchor="start" x="646.45" y="-3396.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="698.02" y="-3396.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="706.91" y="-3396.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="131.11,-3315.37 131.11,-3375.37 748.11,-3375.37 748.11,-3315.37 131.11,-3315.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="131.11,-3315.37 131.11,-3375.37 748.11,-3375.37 748.11,-3315.37 131.11,-3315.37"/>
|
||||
<text text-anchor="start" x="142.11" y="-3335.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">rating    </text>
|
||||
<text text-anchor="start" x="600.22" y="-3336.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">integer</text>
|
||||
<text text-anchor="start" x="698.02" y="-3336.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="706.91" y="-3336.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="131.11,-3255.37 131.11,-3315.37 748.11,-3315.37 748.11,-3255.37 131.11,-3255.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="131.11,-3255.37 131.11,-3315.37 748.11,-3315.37 748.11,-3255.37 131.11,-3255.37"/>
|
||||
<text text-anchor="start" x="142.11" y="-3275.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">created_at    </text>
|
||||
<text text-anchor="start" x="337.1" y="-3276.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="698.02" y="-3276.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="706.91" y="-3276.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="131.11,-3195.37 131.11,-3255.37 748.11,-3255.37 748.11,-3195.37 131.11,-3195.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="131.11,-3195.37 131.11,-3255.37 748.11,-3255.37 748.11,-3195.37 131.11,-3195.37"/>
|
||||
<text text-anchor="start" x="141.78" y="-3215.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">updated_at    </text>
|
||||
<text text-anchor="start" x="337.11" y="-3216.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="698.03" y="-3216.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="706.92" y="-3216.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="129.61,-3194.37 129.61,-3616.37 748.61,-3616.37 748.61,-3194.37 129.61,-3194.37"/>
|
||||
</g>
|
||||
<!-- find_rating->find -->
|
||||
<!-- find_rating->find -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>find_rating:e->find:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M749.11,-3465.37C873.77,-3465.37 833.73,-3597.92 878.23,-3714.37 982.81,-3988.04 753.38,-4351.73 1034.14,-4360.22"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="1034.29,-4363.72 1044.34,-4360.37 1034.39,-4356.72 1034.29,-4363.72"/>
|
||||
<text text-anchor="middle" x="1035.45" y="-4331.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="742.89" y="-3436.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- find_rating->user -->
|
||||
<!-- find_rating->user -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>find_rating:e->user:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M749.11,-3405.37C2285.06,-3405.37 588.06,-1028.22 1828.45,-122.37 1907.26,-64.82 2636.46,-54.61 2706.68,-122.37 2830.51,-241.85 2651.24,-3161.92 2809.61,-3275.94"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="2808.89,-3279.39 2819.48,-3279.37 2811.18,-3272.78 2808.89,-3279.39"/>
|
||||
<text text-anchor="middle" x="2810.59" y="-3288.97" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="742.89" y="-3376.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- friendship -->
|
||||
<g id="friendship" class="node">
|
||||
<title>friendship</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="2267.57" cy="-417.37" rx="433" ry="257.27"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="1963.57,-537.37 1963.57,-597.37 2571.57,-597.37 2571.57,-537.37 1963.57,-537.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-537.37 1963.57,-597.37 2571.57,-597.37 2571.57,-537.37 1963.57,-537.37"/>
|
||||
<text text-anchor="start" x="2135.97" y="-558.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       friendship       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-477.37 1963.57,-537.37 2571.57,-537.37 2571.57,-477.37 1963.57,-477.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-477.37 1963.57,-537.37 2571.57,-537.37 2571.57,-477.37 1963.57,-477.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-498.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="1999.46" y="-498.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="2469.9" y="-498.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2521.48" y="-498.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-498.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-417.37 1963.57,-477.37 2571.57,-477.37 2571.57,-417.37 1963.57,-417.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-417.37 1963.57,-477.37 2571.57,-477.37 2571.57,-417.37 1963.57,-417.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-437.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">user_id    </text>
|
||||
<text text-anchor="start" x="2469.9" y="-438.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2521.48" y="-438.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-438.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-357.37 1963.57,-417.37 2571.57,-417.37 2571.57,-357.37 1963.57,-357.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-357.37 1963.57,-417.37 2571.57,-417.37 2571.57,-357.37 1963.57,-357.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-377.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">friend_id    </text>
|
||||
<text text-anchor="start" x="2469.9" y="-378.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2521.48" y="-378.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-378.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-297.37 1963.57,-357.37 2571.57,-357.37 2571.57,-297.37 1963.57,-297.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-297.37 1963.57,-357.37 2571.57,-357.37 2571.57,-297.37 1963.57,-297.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-317.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">status    </text>
|
||||
<text text-anchor="start" x="2469.9" y="-318.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2521.48" y="-318.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-318.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-237.37 1963.57,-297.37 2571.57,-297.37 2571.57,-237.37 1963.57,-237.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-237.37 1963.57,-297.37 2571.57,-297.37 2571.57,-237.37 1963.57,-237.37"/>
|
||||
<text text-anchor="start" x="1974.2" y="-257.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">created_at    </text>
|
||||
<text text-anchor="start" x="2160.56" y="-258.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="2521.48" y="-258.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-258.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1962.57,-236.37 1962.57,-598.37 2572.57,-598.37 2572.57,-236.37 1962.57,-236.37"/>
|
||||
</g>
|
||||
<!-- friendship->user -->
|
||||
<!-- friendship->user -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>friendship:e->user:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M2572.57,-447.37C2693.21,-447.37 2673.33,-567.43 2706.68,-683.37 2745.69,-818.99 2678.28,-3170.15 2810.08,-3275.7"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="2808.89,-3279 2819.48,-3279.37 2811.43,-3272.48 2808.89,-3279"/>
|
||||
<text text-anchor="middle" x="2828.38" y="-3250.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="2578.79" y="-418.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- friendship->user -->
|
||||
<!-- friendship->user -->
|
||||
<g id="edge22" class="edge">
|
||||
<title>friendship:e->user:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M2572.57,-387.37C2717,-387.37 2673.13,-542.89 2706.68,-683.37 2739.46,-820.63 2678,-3170.23 2810.07,-3275.71"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="2808.89,-3279.01 2819.48,-3279.37 2811.43,-3272.48 2808.89,-3279.01"/>
|
||||
<text text-anchor="middle" x="2828.38" y="-3288.97" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="2578.79" y="-358.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- location->user -->
|
||||
<!-- location->user -->
|
||||
<g id="edge24" class="edge">
|
||||
<title>location:e->user:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M2572.57,-4086.37C2663.04,-4086.37 2721.49,-3335.11 2809.72,-3282.29"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="2810.9,-3285.59 2819.48,-3279.37 2808.9,-3278.88 2810.9,-3285.59"/>
|
||||
<text text-anchor="middle" x="2810.59" y="-3250.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="2578.79" y="-4095.97" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- notification -->
|
||||
<g id="notification" class="node">
|
||||
<title>notification</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="2267.57" cy="-2312.37" rx="433" ry="384.83"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="1963.57,-2522.37 1963.57,-2582.37 2571.57,-2582.37 2571.57,-2522.37 1963.57,-2522.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-2522.37 1963.57,-2582.37 2571.57,-2582.37 2571.57,-2522.37 1963.57,-2522.37"/>
|
||||
<text text-anchor="start" x="2128.85" y="-2543.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       notification       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-2462.37 1963.57,-2522.37 2571.57,-2522.37 2571.57,-2462.37 1963.57,-2462.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-2462.37 1963.57,-2522.37 2571.57,-2522.37 2571.57,-2462.37 1963.57,-2462.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-2483.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="1999.46" y="-2483.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="2469.9" y="-2483.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2521.48" y="-2483.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-2483.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-2402.37 1963.57,-2462.37 2571.57,-2462.37 2571.57,-2402.37 1963.57,-2402.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-2402.37 1963.57,-2462.37 2571.57,-2462.37 2571.57,-2402.37 1963.57,-2402.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-2422.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">user_id    </text>
|
||||
<text text-anchor="start" x="2469.9" y="-2423.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2521.48" y="-2423.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-2423.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-2342.37 1963.57,-2402.37 2571.57,-2402.37 2571.57,-2342.37 1963.57,-2342.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-2342.37 1963.57,-2402.37 2571.57,-2402.37 2571.57,-2342.37 1963.57,-2342.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-2362.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">type    </text>
|
||||
<text text-anchor="start" x="2469.9" y="-2363.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2521.48" y="-2363.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-2363.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-2282.37 1963.57,-2342.37 2571.57,-2342.37 2571.57,-2282.37 1963.57,-2282.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-2282.37 1963.57,-2342.37 2571.57,-2342.37 2571.57,-2282.37 1963.57,-2282.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-2302.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">title    </text>
|
||||
<text text-anchor="start" x="2469.9" y="-2303.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2521.48" y="-2303.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-2303.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-2222.37 1963.57,-2282.37 2571.57,-2282.37 2571.57,-2222.37 1963.57,-2222.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-2222.37 1963.57,-2282.37 2571.57,-2282.37 2571.57,-2222.37 1963.57,-2222.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-2242.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">message    </text>
|
||||
<text text-anchor="start" x="2469.9" y="-2243.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2521.48" y="-2243.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-2243.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-2162.37 1963.57,-2222.37 2571.57,-2222.37 2571.57,-2162.37 1963.57,-2162.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-2162.37 1963.57,-2222.37 2571.57,-2222.37 2571.57,-2162.37 1963.57,-2162.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-2182.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">data    </text>
|
||||
<text text-anchor="start" x="2484.1" y="-2183.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">jsonb</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-2102.37 1963.57,-2162.37 2571.57,-2162.37 2571.57,-2102.37 1963.57,-2102.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-2102.37 1963.57,-2162.37 2571.57,-2162.37 2571.57,-2102.37 1963.57,-2102.37"/>
|
||||
<text text-anchor="start" x="1974.57" y="-2122.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">is_read    </text>
|
||||
<text text-anchor="start" x="2446.73" y="-2123.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1963.57,-2042.37 1963.57,-2102.37 2571.57,-2102.37 2571.57,-2042.37 1963.57,-2042.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1963.57,-2042.37 1963.57,-2102.37 2571.57,-2102.37 2571.57,-2042.37 1963.57,-2042.37"/>
|
||||
<text text-anchor="start" x="1974.2" y="-2062.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">created_at    </text>
|
||||
<text text-anchor="start" x="2160.56" y="-2063.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="2521.48" y="-2063.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2530.37" y="-2063.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1962.57,-2041.37 1962.57,-2583.37 2572.57,-2583.37 2572.57,-2041.37 1962.57,-2041.37"/>
|
||||
</g>
|
||||
<!-- notification->user -->
|
||||
<!-- notification->user -->
|
||||
<g id="edge26" class="edge">
|
||||
<title>notification:e->user:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M2572.57,-2432.37C2707.75,-2432.37 2663.47,-2577.28 2706.68,-2705.37 2747.09,-2825.18 2692.62,-3254.96 2809.23,-3278.37"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="2809.19,-3281.89 2819.48,-3279.37 2809.87,-3274.92 2809.19,-3281.89"/>
|
||||
<text text-anchor="middle" x="2810.59" y="-3288.97" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="2578.79" y="-2403.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- notification_preferences -->
|
||||
<g id="notification_preferences" class="node">
|
||||
<title>notification_preferences</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="2267.57" cy="-3099.37" rx="439.23" ry="384.83"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="1959.57,-3309.37 1959.57,-3369.37 2576.57,-3369.37 2576.57,-3309.37 1959.57,-3309.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-3309.37 1959.57,-3369.37 2576.57,-3369.37 2576.57,-3309.37 1959.57,-3309.37"/>
|
||||
<text text-anchor="start" x="2035.99" y="-3330.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       notification_preferences       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-3249.37 1959.57,-3309.37 2576.57,-3309.37 2576.57,-3249.37 1959.57,-3249.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-3249.37 1959.57,-3309.37 2576.57,-3309.37 2576.57,-3249.37 1959.57,-3249.37"/>
|
||||
<text text-anchor="start" x="1970.57" y="-3270.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">user_id</text>
|
||||
<text text-anchor="start" x="2075.48" y="-3270.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="2474.9" y="-3270.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2526.48" y="-3270.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2535.37" y="-3270.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-3189.37 1959.57,-3249.37 2576.57,-3249.37 2576.57,-3189.37 1959.57,-3189.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-3189.37 1959.57,-3249.37 2576.57,-3249.37 2576.57,-3189.37 1959.57,-3189.37"/>
|
||||
<text text-anchor="start" x="1970.57" y="-3209.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">friend_requests    </text>
|
||||
<text text-anchor="start" x="2451.73" y="-3210.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-3129.37 1959.57,-3189.37 2576.57,-3189.37 2576.57,-3129.37 1959.57,-3129.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-3129.37 1959.57,-3189.37 2576.57,-3189.37 2576.57,-3129.37 1959.57,-3129.37"/>
|
||||
<text text-anchor="start" x="1970.57" y="-3149.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">friend_accepted    </text>
|
||||
<text text-anchor="start" x="2451.73" y="-3150.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-3069.37 1959.57,-3129.37 2576.57,-3129.37 2576.57,-3069.37 1959.57,-3069.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-3069.37 1959.57,-3129.37 2576.57,-3129.37 2576.57,-3069.37 1959.57,-3069.37"/>
|
||||
<text text-anchor="start" x="1970.57" y="-3089.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">find_liked    </text>
|
||||
<text text-anchor="start" x="2451.73" y="-3090.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-3009.37 1959.57,-3069.37 2576.57,-3069.37 2576.57,-3009.37 1959.57,-3009.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-3009.37 1959.57,-3069.37 2576.57,-3069.37 2576.57,-3009.37 1959.57,-3009.37"/>
|
||||
<text text-anchor="start" x="1970.57" y="-3029.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">find_commented    </text>
|
||||
<text text-anchor="start" x="2451.73" y="-3030.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-2949.37 1959.57,-3009.37 2576.57,-3009.37 2576.57,-2949.37 1959.57,-2949.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-2949.37 1959.57,-3009.37 2576.57,-3009.37 2576.57,-2949.37 1959.57,-2949.37"/>
|
||||
<text text-anchor="start" x="1970.57" y="-2969.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">push_enabled    </text>
|
||||
<text text-anchor="start" x="2451.73" y="-2970.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-2889.37 1959.57,-2949.37 2576.57,-2949.37 2576.57,-2889.37 1959.57,-2889.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-2889.37 1959.57,-2949.37 2576.57,-2949.37 2576.57,-2889.37 1959.57,-2889.37"/>
|
||||
<text text-anchor="start" x="1970.57" y="-2909.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">created_at    </text>
|
||||
<text text-anchor="start" x="2165.55" y="-2910.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="2526.48" y="-2910.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2535.37" y="-2910.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-2829.37 1959.57,-2889.37 2576.57,-2889.37 2576.57,-2829.37 1959.57,-2829.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-2829.37 1959.57,-2889.37 2576.57,-2889.37 2576.57,-2829.37 1959.57,-2829.37"/>
|
||||
<text text-anchor="start" x="1970.23" y="-2849.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">updated_at    </text>
|
||||
<text text-anchor="start" x="2165.56" y="-2850.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="2526.48" y="-2850.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2535.37" y="-2850.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1958.07,-2828.37 1958.07,-3370.37 2577.07,-3370.37 2577.07,-2828.37 1958.07,-2828.37"/>
|
||||
</g>
|
||||
<!-- notification_preferences->user -->
|
||||
<!-- notification_preferences->user -->
|
||||
<g id="edge28" class="edge">
|
||||
<title>notification_preferences:e->user:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M2577.57,-3279.37C2681.62,-3279.37 2710.15,-3279.37 2809.33,-3279.37"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="2809.48,-3282.87 2819.48,-3279.37 2809.48,-3275.87 2809.48,-3282.87"/>
|
||||
<text text-anchor="middle" x="2828.38" y="-3250.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="2583.79" y="-3250.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- notification_subscription -->
|
||||
<g id="notification_subscription" class="node">
|
||||
<title>notification_subscription</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="2267.57" cy="-1119.37" rx="439.23" ry="427.19"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="1959.57,-1359.37 1959.57,-1419.37 2576.57,-1419.37 2576.57,-1359.37 1959.57,-1359.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-1359.37 1959.57,-1419.37 2576.57,-1419.37 2576.57,-1359.37 1959.57,-1359.37"/>
|
||||
<text text-anchor="start" x="2035.11" y="-1380.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       notification_subscription       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-1299.37 1959.57,-1359.37 2576.57,-1359.37 2576.57,-1299.37 1959.57,-1299.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-1299.37 1959.57,-1359.37 2576.57,-1359.37 2576.57,-1299.37 1959.57,-1299.37"/>
|
||||
<text text-anchor="start" x="1970.57" y="-1320.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="1995.46" y="-1320.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="2474.9" y="-1320.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2526.48" y="-1320.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2535.37" y="-1320.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-1239.37 1959.57,-1299.37 2576.57,-1299.37 2576.57,-1239.37 1959.57,-1239.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-1239.37 1959.57,-1299.37 2576.57,-1299.37 2576.57,-1239.37 1959.57,-1239.37"/>
|
||||
<text text-anchor="start" x="1970.57" y="-1259.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">user_id    </text>
|
||||
<text text-anchor="start" x="2474.9" y="-1260.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2526.48" y="-1260.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2535.37" y="-1260.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-1179.37 1959.57,-1239.37 2576.57,-1239.37 2576.57,-1179.37 1959.57,-1179.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-1179.37 1959.57,-1239.37 2576.57,-1239.37 2576.57,-1179.37 1959.57,-1179.37"/>
|
||||
<text text-anchor="start" x="1970.57" y="-1199.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">endpoint    </text>
|
||||
<text text-anchor="start" x="2474.9" y="-1200.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2526.48" y="-1200.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2535.37" y="-1200.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-1119.37 1959.57,-1179.37 2576.57,-1179.37 2576.57,-1119.37 1959.57,-1119.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-1119.37 1959.57,-1179.37 2576.57,-1179.37 2576.57,-1119.37 1959.57,-1119.37"/>
|
||||
<text text-anchor="start" x="1970.57" y="-1139.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">p256dh_key    </text>
|
||||
<text text-anchor="start" x="2474.9" y="-1140.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2526.48" y="-1140.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2535.37" y="-1140.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-1059.37 1959.57,-1119.37 2576.57,-1119.37 2576.57,-1059.37 1959.57,-1059.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-1059.37 1959.57,-1119.37 2576.57,-1119.37 2576.57,-1059.37 1959.57,-1059.37"/>
|
||||
<text text-anchor="start" x="1970.57" y="-1079.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">auth_key    </text>
|
||||
<text text-anchor="start" x="2474.9" y="-1080.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2526.48" y="-1080.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2535.37" y="-1080.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-999.37 1959.57,-1059.37 2576.57,-1059.37 2576.57,-999.37 1959.57,-999.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-999.37 1959.57,-1059.37 2576.57,-1059.37 2576.57,-999.37 1959.57,-999.37"/>
|
||||
<text text-anchor="start" x="1970.57" y="-1019.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">user_agent    </text>
|
||||
<text text-anchor="start" x="2513.99" y="-1020.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-939.37 1959.57,-999.37 2576.57,-999.37 2576.57,-939.37 1959.57,-939.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-939.37 1959.57,-999.37 2576.57,-999.37 2576.57,-939.37 1959.57,-939.37"/>
|
||||
<text text-anchor="start" x="1970.57" y="-959.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">is_active    </text>
|
||||
<text text-anchor="start" x="2451.73" y="-960.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-879.37 1959.57,-939.37 2576.57,-939.37 2576.57,-879.37 1959.57,-879.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-879.37 1959.57,-939.37 2576.57,-939.37 2576.57,-879.37 1959.57,-879.37"/>
|
||||
<text text-anchor="start" x="1970.57" y="-899.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">created_at    </text>
|
||||
<text text-anchor="start" x="2165.55" y="-900.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="2526.48" y="-900.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2535.37" y="-900.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1959.57,-819.37 1959.57,-879.37 2576.57,-879.37 2576.57,-819.37 1959.57,-819.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1959.57,-819.37 1959.57,-879.37 2576.57,-879.37 2576.57,-819.37 1959.57,-819.37"/>
|
||||
<text text-anchor="start" x="1970.23" y="-839.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">updated_at    </text>
|
||||
<text text-anchor="start" x="2165.56" y="-840.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="2526.48" y="-840.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2535.37" y="-840.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1958.07,-818.37 1958.07,-1420.37 2577.07,-1420.37 2577.07,-818.37 1958.07,-818.37"/>
|
||||
</g>
|
||||
<!-- notification_subscription->user -->
|
||||
<!-- notification_subscription->user -->
|
||||
<g id="edge30" class="edge">
|
||||
<title>notification_subscription:e->user:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M2577.57,-1269.37C2717.03,-1269.37 2672.89,-1420.06 2706.68,-1555.37 2752.35,-1738.25 2632,-3224.25 2809.38,-3277.88"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="2809.08,-3281.37 2819.48,-3279.37 2810.1,-3274.45 2809.08,-3281.37"/>
|
||||
<text text-anchor="middle" x="2828.38" y="-3288.97" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="2583.79" y="-1240.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- session -->
|
||||
<g id="session" class="node">
|
||||
<title>session</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="2267.57" cy="-1737.37" rx="430.76" ry="172.57"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="1965.57,-1797.37 1965.57,-1857.37 2570.57,-1857.37 2570.57,-1797.37 1965.57,-1797.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1965.57,-1797.37 1965.57,-1857.37 2570.57,-1857.37 2570.57,-1797.37 1965.57,-1797.37"/>
|
||||
<text text-anchor="start" x="2151.58" y="-1818.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       session       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1965.57,-1737.37 1965.57,-1797.37 2570.57,-1797.37 2570.57,-1737.37 1965.57,-1737.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1965.57,-1737.37 1965.57,-1797.37 2570.57,-1797.37 2570.57,-1737.37 1965.57,-1737.37"/>
|
||||
<text text-anchor="start" x="1976.57" y="-1758.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="2001.46" y="-1758.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="2468.9" y="-1758.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2520.48" y="-1758.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2529.37" y="-1758.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1965.57,-1677.37 1965.57,-1737.37 2570.57,-1737.37 2570.57,-1677.37 1965.57,-1677.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1965.57,-1677.37 1965.57,-1737.37 2570.57,-1737.37 2570.57,-1677.37 1965.57,-1677.37"/>
|
||||
<text text-anchor="start" x="1976.57" y="-1697.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">user_id    </text>
|
||||
<text text-anchor="start" x="2468.9" y="-1698.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<text text-anchor="start" x="2520.48" y="-1698.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2529.37" y="-1698.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1965.57,-1617.37 1965.57,-1677.37 2570.57,-1677.37 2570.57,-1617.37 1965.57,-1617.37"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1965.57,-1617.37 1965.57,-1677.37 2570.57,-1677.37 2570.57,-1617.37 1965.57,-1617.37"/>
|
||||
<text text-anchor="start" x="1976.49" y="-1637.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">expires_at    </text>
|
||||
<text text-anchor="start" x="2159.56" y="-1638.57" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamp with time zone</text>
|
||||
<text text-anchor="start" x="2520.48" y="-1638.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="2529.37" y="-1638.57" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1964.07,-1616.37 1964.07,-1858.37 2571.07,-1858.37 2571.07,-1616.37 1964.07,-1616.37"/>
|
||||
</g>
|
||||
<!-- session->user -->
|
||||
<!-- session->user -->
|
||||
<g id="edge32" class="edge">
|
||||
<title>session:e->user:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M2571.57,-1707.37C2682.92,-1707.37 2671,-1812.88 2706.68,-1918.37 2754.2,-2058.88 2671.6,-3225.23 2809.61,-3277.55"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="2809.01,-3281 2819.48,-3279.37 2810.28,-3274.12 2809.01,-3281"/>
|
||||
<text text-anchor="middle" x="2810.59" y="-3250.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="2577.79" y="-1678.57" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 86 KiB |
19646
docs/main.pdf
Normal file
19646
docs/main.pdf
Normal file
File diff suppressed because it is too large
Load Diff
93
docs/main.typ
Normal file
93
docs/main.typ
Normal file
@@ -0,0 +1,93 @@
|
||||
// Author: van Nes Zias
|
||||
// Date: 26-dec-2025
|
||||
// Serengo
|
||||
|
||||
#set document(
|
||||
title: "Serengo",
|
||||
author: "Zias van Nes",
|
||||
)
|
||||
|
||||
// Page setup with margins and header/footer
|
||||
#set page(
|
||||
paper: "a4",
|
||||
margin: 3cm,
|
||||
header: context {
|
||||
let elems = query(heading)
|
||||
.filter(h => h.location().position().page <= here().position().page)
|
||||
let chapter = if elems != () {
|
||||
emph(elems.last().body)
|
||||
}
|
||||
align(right, chapter)
|
||||
},
|
||||
numbering: "1",
|
||||
)
|
||||
|
||||
// Text settings - 1.5 line spacing
|
||||
#set par(
|
||||
leading: 0.65em,
|
||||
justify: true,
|
||||
first-line-indent: 1.8em,
|
||||
)
|
||||
|
||||
// Section numbering (1, 2, 3...)
|
||||
#set heading(numbering: "1.")
|
||||
|
||||
// Title page
|
||||
#align(center)[
|
||||
#text(size: 20pt, weight: "bold")[Serengo]
|
||||
#v(0.8em)
|
||||
#text(size: 12pt)[Projectdocumentatie]
|
||||
|
||||
#v(2em)
|
||||
|
||||
#text(size: 12pt)[Zias van Nes]
|
||||
#v(0.5em)
|
||||
#text(size: 11pt)[Toegepaste Informatica, Odisee Hogeschool, Brussel]
|
||||
|
||||
#v(1em)
|
||||
|
||||
#datetime.today().display()
|
||||
]
|
||||
|
||||
#pagebreak()
|
||||
|
||||
// Abstract
|
||||
#align(center)[
|
||||
#text(size: 12pt, weight: "bold")[Samenvatting]
|
||||
]
|
||||
|
||||
#par(first-line-indent: 0pt)[
|
||||
Serengo is een locatie-gebaseerde sociale webapplicatie waarmee gebruikers zogenaamde 'finds'
|
||||
(plaatsen en momenten) op een kaart kunnen vastleggen, verrijken met media en delen met een
|
||||
vertrouwde kring. Deze paper beschrijft de doelstelling en doelgroep van het project, de
|
||||
onderliggende data- en software-architectuur, de gebruikte tools en ontwikkelworkflow, de
|
||||
deploymentaanpak en de belangrijkste optimalisaties die tijdens de ontwikkeling zijn uitgevoerd.
|
||||
]
|
||||
|
||||
#pagebreak()
|
||||
|
||||
|
||||
// Table of contents
|
||||
#outline(
|
||||
title: "Inhoudstafel",
|
||||
indent: auto,
|
||||
)
|
||||
|
||||
#pagebreak()
|
||||
|
||||
// Include all sections
|
||||
|
||||
#include "sections/wat-is-serengo.typ"
|
||||
#include "sections/voor-wie-is-serengo.typ"
|
||||
#include "sections/erd.typ"
|
||||
#include "sections/klassediagram.typ"
|
||||
#include "sections/architectuur.typ"
|
||||
#include "sections/buildtools.typ"
|
||||
#include "sections/deployment.typ"
|
||||
#include "sections/optimalisaties.typ"
|
||||
#include "sections/screenshots.typ"
|
||||
|
||||
#pagebreak()
|
||||
|
||||
// Bibliography
|
||||
#bibliography("bib/main.bib", style: "apa", title: "Referenties")
|
||||
6
docs/screenshots/find-detail.svg
Normal file
6
docs/screenshots/find-detail.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="675" viewBox="0 0 1200 675">
|
||||
<rect width="1200" height="675" fill="#f2f2f2" stroke="#222" stroke-width="4" />
|
||||
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="42" fill="#222">
|
||||
Screenshot placeholder: find-detail
|
||||
</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 350 B |
6
docs/screenshots/friends.svg
Normal file
6
docs/screenshots/friends.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="675" viewBox="0 0 1200 675">
|
||||
<rect width="1200" height="675" fill="#f2f2f2" stroke="#222" stroke-width="4" />
|
||||
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="42" fill="#222">
|
||||
Screenshot placeholder: friends
|
||||
</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 346 B |
6
docs/screenshots/home.svg
Normal file
6
docs/screenshots/home.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="675" viewBox="0 0 1200 675">
|
||||
<rect width="1200" height="675" fill="#f2f2f2" stroke="#222" stroke-width="4" />
|
||||
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="42" fill="#222">
|
||||
Screenshot placeholder: home
|
||||
</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 343 B |
6
docs/screenshots/mobile.svg
Normal file
6
docs/screenshots/mobile.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="675" viewBox="0 0 1200 675">
|
||||
<rect width="1200" height="675" fill="#f2f2f2" stroke="#222" stroke-width="4" />
|
||||
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="42" fill="#222">
|
||||
Screenshot placeholder: mobile
|
||||
</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 345 B |
6
docs/screenshots/notifications.svg
Normal file
6
docs/screenshots/notifications.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="675" viewBox="0 0 1200 675">
|
||||
<rect width="1200" height="675" fill="#f2f2f2" stroke="#222" stroke-width="4" />
|
||||
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="42" fill="#222">
|
||||
Screenshot placeholder: notifications
|
||||
</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 352 B |
98
docs/sections/architectuur.typ
Normal file
98
docs/sections/architectuur.typ
Normal file
@@ -0,0 +1,98 @@
|
||||
#heading[Architectuur van het project]
|
||||
|
||||
De architectuur van Serengo is opgebouwd rond SvelteKit als full-stack framework, Drizzle ORM voor de
|
||||
PostgreSQL-database en een aantal gespecialiseerde services voor storage, kaarten en notificaties. De frontend en backend leven in dezelfde codebase en delen type-informatie, zodat de volledige stack strongly typed is.
|
||||
|
||||
== Opbouw van de applicatie
|
||||
|
||||
Op hoog niveau bestaat de applicatie uit de volgende lagen:
|
||||
|
||||
- *Presentatielaag (UI)* – Svelte 5-componenten in `src/lib/components` en pagina's in
|
||||
`src/routes`. Componenten zijn per domein gegroepeerd (auth, finds, map, media, notifications,
|
||||
profile, ...).
|
||||
- *Domein- en servicelaag* – Svelte stores en hulpfuncties in `src/lib/stores` en
|
||||
`src/lib/utils`, plus server-side services in `src/lib/server` (auth, db, media-processor,
|
||||
push, R2, oauth).
|
||||
- *API-laag* – SvelteKit-endpoints in `src/routes/api/*` die CRUD- en acties aanbieden voor
|
||||
finds, friends, users, notifications, profile pictures, places en media.
|
||||
- *Datalaag* – een PostgreSQL-database aangestuurd via Drizzle ORM. De schema-definitie staat in
|
||||
`src/lib/server/db/schema.ts`, migraties in de map `drizzle/`.
|
||||
|
||||
Deze lagen zijn zodanig opgebouwd dat UI-componenten alleen via duidelijke interfaces praten met
|
||||
stores en services, en dat alle persistente data via de Drizzle-laag loopt.
|
||||
|
||||
== Projectstructuur
|
||||
|
||||
De belangrijkste mappen van het project zijn:
|
||||
.
|
||||
- `src/lib/components/` – herbruikbare UI-componenten, gegroepeerd per domein:
|
||||
- `auth/` – login-form en gerelateerde auth-componenten.
|
||||
- `finds/` – componenten rond finds (overzichten, detailweergave, editmodals, comment-UI, ...).
|
||||
- `map/` – kaartcomponenten (Map, LocationManager, POI-zoekfunctionaliteit).
|
||||
- `media/` – video- en mediacomponenten.
|
||||
- `notifications/` – notificatie-UI en beheer.
|
||||
- `profile/` – profielpaneel en profielfoto’s.
|
||||
- plus een set shadcn-achtige UI-primitieven [@shadcn-svelte] (button, card, dropdown-menu,
|
||||
sheet, skeleton, sonner, ...).
|
||||
- `src/lib/server/` – server-side logica:
|
||||
- `db/` – databaseconfiguratie en Drizzle-schema.
|
||||
- `auth.ts` – Lucia-authenticatie. [@lucia-docs]
|
||||
- `oauth.ts` – Google OAuth-integratie.
|
||||
- `push.ts` – Web Push-notificaties.
|
||||
- `r2.ts` – integratie met Cloudflare R2.
|
||||
- `media-processor.ts` – beeld- en videobewerking (o.a. WebP/JPEG-pipeline).
|
||||
- `src/lib/stores/` – Svelte stores:
|
||||
- `api-sync.ts` – centrale sync-service voor optimistic updates.
|
||||
- `location.ts` – tracking van de huidige gebruikerslocatie.
|
||||
- `src/lib/utils/` – hulpfuncties, o.a. `geolocation.ts` en `places.ts` (Google Places API).
|
||||
- `src/routes/` – pagina's en API-endpoints:
|
||||
- `+page.svelte` – homepage met de kaart en finds.
|
||||
- `finds/`, `friends/`, `login/`, ... – feature-specifieke pagina's.
|
||||
- `api/` – submappen voor finds, friends, users, notifications, profile-picture, places, media,
|
||||
...
|
||||
- `drizzle/` – migratiebestanden en metadata.
|
||||
- `static/` – statische assets (fonts, map-styles, afbeeldingen, manifest, robots.txt, ...).
|
||||
- `scripts/` – hulpscripts (zoals het genereren van VAPID-keys).
|
||||
|
||||
== Location-gecentreerde architectuur
|
||||
|
||||
Eén van de belangrijkste architecturale keuzes is de overstap naar een *location-gecentreerd
|
||||
architectuurmodel*. In plaats van elke find zijn eigen, duplicerende locatiedata te laten opslaan,
|
||||
worden locaties in een aparte `locations`-tabel beheerd. Meerdere finds kunnen aan dezelfde locatie
|
||||
gekoppeld worden. Dit heeft meerdere voordelen:
|
||||
|
||||
- *Data-normalisatie* – locatiegegevens (coördinaten, naam, type) worden op één plaats beheerd.
|
||||
- *Betere performance* – queries kunnen efficiënter filteren en groeperen op locatie.
|
||||
- *Functionaliteit per locatie* – het wordt eenvoudiger om alle finds op één plek te combineren en hier extra functionaliteit rond te bouwen (bijv. populariteitsmetrieken in de toekomst).
|
||||
|
||||
De grote logic overhaul (Phase 6–7 in het logboek) beschrijft hoe de bestaande finds-architectuur
|
||||
werd omgevormd naar dit model, inclusief migraties en aanpassingen op zowel API als frontend.
|
||||
|
||||
== Sync-service en api-sync store
|
||||
|
||||
Om de gebruikerservaring soepel te houden, maakt Serengo gebruik van een *sync-service* en een
|
||||
centrale `api-sync` store. In plaats van bij elke wijziging te wachten op een serverrespons, wordt
|
||||
het volgende patroon gebruikt:
|
||||
|
||||
1. De gebruiker voert een actie uit (bijvoorbeeld een find aanpassen of een comment toevoegen).
|
||||
2. De wijziging wordt onmiddellijk lokaal toegepast (optimistic update) zodat de UI instant reageert.
|
||||
3. De sync-service stuurt de wijziging naar de API.
|
||||
4. Bij succes wordt de lokale staat bevestigd; bij een fout wordt de wijziging teruggedraaid (rollback) en ziet de gebruiker een duidelijke foutmelding.
|
||||
|
||||
Deze architectuur zorgt voor een responsieve interface, zelfs bij netwerkvertraging, en centraliseert
|
||||
state management voor finds, comments, likes en ratings.
|
||||
|
||||
In de toekomst zou ik hier eventueel WebSockets aan kunnen toevoegen voor real-time updates tussen gebruikers. Waarschijnlijk zou het ook interessant zijn om hiervoor te kijken naar een externe service. Ik kijk hierbij naar Convex [@convex-docs] die real-time sync en offline-first functionaliteit biedt zodat dit niet allemaal zelf gebouwd en onderhouden hoeft te worden.
|
||||
|
||||
== Integratie met externe diensten
|
||||
|
||||
De architectuur integreert verschillende externe diensten op een consistente manier:
|
||||
|
||||
- *Cloudflare R2* voor opslag van media, benaderd via de `r2.ts`-service en beveiligde signed
|
||||
URLs.
|
||||
- *Google OAuth* voor authenticatie, afgehandeld via `oauth.ts` in combinatie met Lucia [@lucia-docs].
|
||||
- *Google Places API* voor POI-zoekfunctionaliteit, gebruikt door de map- en locatiecomponenten.
|
||||
- *Web Push* voor notificaties, met VAPID-keys en een service worker die push-events verwerkt.
|
||||
|
||||
Elke integratie is ondergebracht in een eigen module of service, zodat de invloed op de rest van het
|
||||
systeem beperkt en overzichtelijk blijft.
|
||||
70
docs/sections/buildtools.typ
Normal file
70
docs/sections/buildtools.typ
Normal file
@@ -0,0 +1,70 @@
|
||||
#heading[Buildtools en ontwikkelcommando's]
|
||||
|
||||
Serengo maakt gebruik van een moderne JavaScript-toolchain gebaseerd op SvelteKit en Vite, aangevuld met TypeScript, ESLint/Prettier en Drizzle voor databasebeheer [@sveltekit-docs; @vite-docs; @drizzle-docs]. In dit hoofdstuk worden de belangrijkste tools en commando's samengevat.
|
||||
|
||||
== Bundling en framework
|
||||
|
||||
- *Framework*: SvelteKit 2 met Svelte 5-componenten en runes (`$props`, `$derived`, `$effect`).
|
||||
- *Bundler/dev-server*: Vite 7, geconfigureerd in `vite.config.ts`.
|
||||
- *Adapter*: `@sveltejs/adapter-node` voor een Node.js-productieserver (`svelte.config.js`).
|
||||
|
||||
De bundling gebeurt via Vite: tijdens ontwikkeling draait een snelle dev-server met hot module replacement; voor productie wordt een geoptimaliseerde bundel gebouwd met code-splitting en tree-shaking.
|
||||
|
||||
== Ontwikkelcommando's (pnpm scripts)
|
||||
|
||||
De belangrijkste commando's (zie `package.json`) zijn:
|
||||
|
||||
- `pnpm run dev`
|
||||
- Start de Vite dev-server met SvelteKit in ontwikkelmodus.
|
||||
- Handig tijdens actieve ontwikkeling; herlaadt automatisch bij codewijzigingen.
|
||||
|
||||
- `pnpm run build`
|
||||
- Maakt een productiebuild van de applicatie.
|
||||
- Gebruikt Vite + SvelteKit om geoptimaliseerde JavaScript en CSS te genereren.
|
||||
|
||||
- `pnpm run preview`
|
||||
- Start een lokale server bovenop de productiebuild.
|
||||
- Wordt gebruikt om de uiteindelijke build te testen voor deployment.
|
||||
|
||||
- `pnpm run check`
|
||||
- Voert `svelte-kit sync` en vervolgens `svelte-check` uit met de `tsconfig.json`.
|
||||
- Controleert TypeScript-typen en Svelte-componenten op fouten.
|
||||
|
||||
- `pnpm run lint`
|
||||
- Voert eerst `prettier --check .` en daarna `eslint .` uit.
|
||||
- Zorgt voor consistente code-stijl en detecteert mogelijke probleemgevallen.
|
||||
|
||||
- `pnpm run format`
|
||||
- Draait Prettier in schrijfmodus (`--write`) over het project.
|
||||
- Past de afgesproken formatteringsregels (tabs, single quotes, max 100 chars) toe.
|
||||
|
||||
== Databasetools (Drizzle ORM)
|
||||
|
||||
Voor het beheer van de PostgreSQL-database wordt Drizzle ORM gebruikt, met bijhorende CLI-commando's:
|
||||
|
||||
- `pnpm run db:start`
|
||||
- Start de PostgreSQL-database via `docker-compose` (zie `docker-compose.yml`).
|
||||
|
||||
- `pnpm run db:generate`
|
||||
- Genereert migratiebestanden op basis van wijzigingen in het Drizzle-schema (`src/lib/server/db/schema.ts`).
|
||||
|
||||
- `pnpm run db:migrate`
|
||||
- Voert de gegenereerde migraties uit op de database.
|
||||
- Wordt zowel lokaal als in de Docker-deployment gebruikt (entrypoint script).
|
||||
|
||||
- `pnpm run db:push`
|
||||
- Pusht de huidige schema-definitie naar de database (handig in vroege ontwikkelfase).
|
||||
|
||||
- `pnpm run db:studio`
|
||||
- Start Drizzle Studio voor het visueel inspecteren van de database.
|
||||
|
||||
- `pnpm run db:generate-erd`
|
||||
- Gebruikt `drizzle-erd` om op basis van het schema een ERD (`erd.svg`) te genereren.
|
||||
|
||||
== ESLint, Prettier en typechecking
|
||||
|
||||
- *ESLint*: bewaakt codekwaliteit en dwingt consistente patterns af, met ondersteuning voor Svelte (`eslint-plugin-svelte`) en moderne JavaScript/TypeScript-regels.
|
||||
- *Prettier*: zorgt voor automatische formattering met de in `AGENTS.md` vastgelegde stijl.
|
||||
- *TypeScript + svelte-check*: zorgen voor statische typeveiligheid doorheen de hele stack.
|
||||
|
||||
Samen vormen deze tools een sterke ontwikkelbasis: fouten worden vroegtijdig opgespoord, de code blijft leesbaar en het buildproces is voorspelbaar en reproduceerbaar.
|
||||
86
docs/sections/deployment.typ
Normal file
86
docs/sections/deployment.typ
Normal file
@@ -0,0 +1,86 @@
|
||||
#heading[Deployment stappen]
|
||||
|
||||
Serengo ondersteunt meerdere deployment-scenario's, waaronder Vercel en een self-hosted Docker-omgeving [@docker-docs]. In dit hoofdstuk worden de belangrijkste concepten, vereiste configuratie en een concreet stappenplan beschreven.
|
||||
|
||||
== Vereiste environment-variabelen
|
||||
|
||||
Voor een werkende productieomgeving zijn minimaal de volgende variabelen nodig (zie ook `logs/logboek.md`):
|
||||
|
||||
```bash
|
||||
DATABASE_URL= # PostgreSQL-verbinding
|
||||
GOOGLE_CLIENT_ID= # Google OAuth client ID
|
||||
GOOGLE_CLIENT_SECRET= # Google OAuth secret
|
||||
R2_ACCOUNT_ID= # Cloudflare R2 account ID
|
||||
R2_ACCESS_KEY_ID= # Cloudflare R2 access key
|
||||
R2_SECRET_ACCESS_KEY= # Cloudflare R2 secret key
|
||||
R2_BUCKET_NAME= # Cloudflare R2 bucket-naam
|
||||
VAPID_PUBLIC_KEY= # Web Push public key
|
||||
VAPID_PRIVATE_KEY= # Web Push private key
|
||||
GOOGLE_MAPS_API_KEY= # Google Places API key
|
||||
```
|
||||
|
||||
Deze worden tijdens build en runtime ingelezen door de SvelteKit-app en de server-side services (`auth`, `r2`, `push`, `places`).
|
||||
|
||||
== Vercel-deployment (cloud)
|
||||
|
||||
In een Vercel-scenario wordt de app gedeployed met behulp van `@sveltejs/adapter-vercel` (aanwezig als dependency). Belangrijke aandachtspunten:
|
||||
|
||||
- De SvelteKit-app wordt als serverless of edge-functies uitgerold, afhankelijk van de Vercel-configuratie.
|
||||
- `DATABASE_URL` moet verwijzen naar een publiek bereikbare PostgreSQL-instantie (bijv. een managed database).
|
||||
- Cloudflare R2 en Web Push blijven extern; de nodige secrets worden als Vercel environment-variabelen ingesteld.
|
||||
|
||||
== Self-hosted Docker-deployment
|
||||
|
||||
Voor een zelfgehoste omgeving is een uitgebreide Docker-setup voorzien (Phase 7 in het logboek):
|
||||
|
||||
- Multi-stage Docker build om een compacte productie-image te maken.
|
||||
- Health checks om de beschikbaarheid van de container te monitoren.
|
||||
- Een entrypoint-script dat bij het starten van de container automatisch Drizzle-migraties uitvoert.
|
||||
- Drizzle als production dependency, zodat migraties ook in de container kunnen draaien.
|
||||
|
||||
Typische stappen voor een self-hosted deployment zijn:
|
||||
|
||||
1. Zorg voor een draaiende PostgreSQL-instantie (lokaal, via `docker-compose` of extern) en vul de `DATABASE_URL` correct in.
|
||||
2. Stel alle vereiste environment-variabelen in voor de app (zie boven).
|
||||
3. Bouw de Docker-image, bijvoorbeeld met:
|
||||
|
||||
```bash
|
||||
docker build -t serengo:latest .
|
||||
```
|
||||
|
||||
4. Start de container met de juiste environment-variabelen en netwerkconfiguratie, bijvoorbeeld via
|
||||
`docker-compose`:
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
5. Het entrypoint-script in `docker-entrypoint.sh` zorgt ervoor dat `pnpm run db:migrate` (of een equivalent via `drizzle-kit`) uitgevoerd wordt bij het opstarten, zodat de database-schema's up-to-date zijn.
|
||||
6. Controleer de logs en health checks om na te gaan of de app correct draait.
|
||||
|
||||
== Van ontwikkeling naar productie
|
||||
|
||||
Samengevat ziet de route van lokale ontwikkeling naar productie er als volgt uit:
|
||||
|
||||
1. Lokaal ontwikkelen met `pnpm run dev`, frequent linten en typen checken (`pnpm run lint`, `pnpm run check`).
|
||||
2. Database- en schemawijzigingen doorvoeren met Drizzle (`db:generate`, `db:migrate`, `db:generate-erd`).
|
||||
3. De productiebuild genereren met `pnpm run build` en lokaal testen via `pnpm run preview`.
|
||||
4. Deployen naar Vercel of bouwen en uitrollen van de Docker-image in een self-hosted omgeving.
|
||||
|
||||
Door de geautomatiseerde migraties en consistente configuratie is het deploymentproces herhaalbaar en betrouwbaar.
|
||||
|
||||
== Aanvullende documentatie en hosting
|
||||
|
||||
Naast deze paper is er een aparte API-referentie beschikbaar, opgebouwd met Mintlify en gehost op mijn eigen domein:
|
||||
|
||||
- *API-documentatie*: `https://docs.zias.be` – Mintlify-documentatie [@mintlify-docs] voor de Serengo-API.
|
||||
|
||||
De volledige broncode van Serengo wordt self-hosted op mijn eigen Git-server:
|
||||
|
||||
- *Broncode-repository*: `https://git.zias.be/zias/serengo` – privé Git-instantie met de volledige Serengo broncode.
|
||||
|
||||
De productieversie van de Serengo-applicatie draait op mijn eigen Hetzner VPS [@hetzner-cloud], uitgerold met Docker [@docker-docs]:
|
||||
|
||||
- *Live-applicatie*: `https://serengo.zias.be` – SvelteKit-app in Docker-container op een Hetzner VPS.
|
||||
|
||||
Deze deployment zorgt ervoor dat zowel de code als de infrastructuur volledig in eigen beheer zijn, zonder afhankelijkheid van publieke Git-hosting of PaaS-platformen.
|
||||
54
docs/sections/erd.typ
Normal file
54
docs/sections/erd.typ
Normal file
@@ -0,0 +1,54 @@
|
||||
#heading[ERD]
|
||||
|
||||
In dit hoofdstuk wordt het Entity-Relationship Diagram (ERD) van de PostgreSQL-database toegelicht. Het ERD is automatisch gegenereerd op basis van het Drizzle-schema (`src/lib/server/db/schema.ts`) en is als `erd.svg` toegevoegd aan de repository.
|
||||
|
||||
#figure(
|
||||
image("../erd.svg"),
|
||||
caption: [Globale ERD van de Serengo-database]
|
||||
)
|
||||
|
||||
De database is ontworpen rond een aantal kernentiteiten die samen het sociale, locatie-gebaseerde karakter van Serengo ondersteunen.
|
||||
|
||||
== Kernentiteiten
|
||||
|
||||
De belangrijkste tabellen zijn:
|
||||
|
||||
- *users* – bevat gebruikersaccounts, inclusief referenties naar authenticatiegegevens (Lucia)[@lucia-docs] en profielinformatie.
|
||||
- *sessions* – beheert actieve sessies voor gebruikers.
|
||||
- *oauth_accounts* – slaat externe OAuth-accounts op (zoals Google) die aan een user gekoppeld zijn.
|
||||
- *locations* – beschrijft gedeelde locaties met o.a. coördinaten, naam en type.
|
||||
- *finds* – posts die aan een locatie gekoppeld zijn, met titel, beschrijving, privacy-instelling en metadata.
|
||||
- *media* (impliciet in het schema afhankelijk van de definitie) – verwijzingen naar geüploade afbeeldingen en video's in Cloudflare R2.
|
||||
- *likes* – registreren welke gebruiker welke find leuk vindt.
|
||||
- *comments* – reacties van gebruikers bij finds.
|
||||
- *friendships* – vriendschapsrelaties en hun status (bijv. pending, accepted, rejected).
|
||||
- *ratings* – numerieke beoordelingen (1–5 sterren) die gebruikers aan finds geven.
|
||||
- *notification_subscriptions* – Web Push-abonnementen (endpoint + keys) per gebruiker/apparaat.
|
||||
- *notification_preferences* – instellingen per gebruiker voor welke notificaties gewenst zijn.
|
||||
|
||||
== Belangrijkste relaties
|
||||
|
||||
Een aantal relaties zijn cruciaal voor het gedrag van de applicatie:
|
||||
|
||||
- Eén *user* heeft veel *finds*; elke find hoort bij precies één user (de eigenaar).
|
||||
- Eén *location* heeft veel *finds*; meerdere users kunnen finds aan dezelfde locatie koppelen.
|
||||
- Eén *find* heeft veel *likes*, *comments* en *ratings*.
|
||||
- Eén *user* heeft veel *likes*, *comments* en *ratings* verspreid over verschillende finds.
|
||||
- *friendships* modelleren wederzijdse relaties tussen twee users; hieruit volgt welke finds zichtbaar zijn bij privacyfilters.
|
||||
- *notification_subscriptions* en *notification_preferences* zijn aan users gekoppeld en bepalen hoe en wanneer pushnotificaties verstuurd worden.
|
||||
|
||||
Samen vormen deze relaties het fundament voor de sociale interacties rond locaties: het ERD maakt zichtbaar hoe gebruikers, locaties, finds en interacties logisch met elkaar verbonden zijn.
|
||||
|
||||
== Normalisatie en evolutie van het datamodel
|
||||
|
||||
Tijdens de ontwikkeling is het datamodel geëvolueerd van een eenvoudiger structuur naar een meer genormaliseerde, location-gecentreerde architectuur (zie ook het hoofdstuk Architectuur). Belangrijke stappen hierin waren:
|
||||
|
||||
- Het verplaatsen van locatienamen en -informatie uit de *finds*-tabel naar een aparte *locations*-tabel, zodat meerdere finds dezelfde locatie kunnen delen.
|
||||
- Het toevoegen van aparte tabellen voor *comments*, *likes* en *ratings*, in plaats van alles in één "finds"-structuur te stoppen.
|
||||
- Het uitbreiden van notificatie- en privacygerelateerde tabellen om Web Push en friend-based zichtbaarheid te ondersteunen.
|
||||
|
||||
Deze normalisatie heeft als effect dat:
|
||||
|
||||
- data-integriteit verbeterd is (minder duplicatie, duidelijke foreign keys);
|
||||
- queries efficiënter en expressiever worden (bijv. alle finds op een locatie, alle activiteiten van een user);
|
||||
- nieuwe features (zoals locatiepopulariteit of uitgebreidere statistieken) eenvoudiger in te passen zijn op basis van het bestaande schema.
|
||||
53
docs/sections/klassediagram.typ
Normal file
53
docs/sections/klassediagram.typ
Normal file
@@ -0,0 +1,53 @@
|
||||
#heading[Klassediagram]
|
||||
|
||||
In dit hoofdstuk wordt een logisch klassediagram gepresenteerd dat de belangrijkste domeinmodellen (typen) van Serengo samenvat. Hoewel de implementatie in TypeScript + Drizzle ORM gebeurt in plaats van klassieke OOP-klassen, kunnen we de structuur voorstellen als een verzameling klassen met velden en relaties. Dit klassediagram sluit nauw aan op het ERD, maar benadrukt vooral de verantwoordelijkheid per type in de applicatielogica.
|
||||
|
||||
== Overzicht van domeinmodellen
|
||||
|
||||
De kernmodellen zijn:
|
||||
|
||||
- *User*
|
||||
- Velden: id, naam, e-mailadres, avatar/profielfoto, aanmaakdatum, OAuth-gegevens.
|
||||
- Verantwoordelijkheid: vertegenwoordigt een eindgebruiker; koppelt naar sessies, find-activiteit en sociale relaties.
|
||||
|
||||
- *Location*
|
||||
- Velden: id, naam, beschrijving (optioneel), coördinaten (latitude, longitude), type/categorie.
|
||||
- Verantwoordelijkheid: beschrijft een fysieke plaats op de kaart waarop meerdere finds kunnen worden geprojecteerd.
|
||||
|
||||
- *Find*
|
||||
- Velden: id, eigenaar (user-id), location-id, titel, beschrijving, privacy-instelling, timestamps, verwijzingen naar media.
|
||||
- Verantwoordelijkheid: vormt de kern-"post" in de applicatie: een verhaal + media gekoppeld aan een locatie.
|
||||
|
||||
- *MediaItem*
|
||||
- Velden: id, find-id, type (afbeelding/video), url (naar R2), fallback-url, metadata (bijv. formaat, grootte).
|
||||
- Verantwoordelijkheid: encapsuleert één mediabestand; zorgt voor scheiding tussen inhoud (find) en opslag (R2).
|
||||
|
||||
- *Comment*
|
||||
- Velden: id, find-id, user-id, inhoud, aanmaakdatum.
|
||||
- Verantwoordelijkheid: laat gebruikers reageren op finds; gekoppeld aan de API-sync-laag voor realtime updates.
|
||||
|
||||
- *Like*
|
||||
- Velden: id, find-id, user-id, timestamp.
|
||||
- Verantwoordelijkheid: registreert een "vind-ik-leuk"-actie op een find.
|
||||
|
||||
- *Rating*
|
||||
- Velden: id, find-id, user-id, waarde (1–5), timestamp.
|
||||
- Verantwoordelijkheid: legt een expliciete beoordeling van een find vast, los van likes.
|
||||
|
||||
- *Friendship*
|
||||
- Velden: id, requester-id, addressee-id, status (pending, accepted, rejected), timestamps.
|
||||
- Verantwoordelijkheid: modelleert de vriendrelatie en vormt de basis voor privacy-bewuste filtering.
|
||||
|
||||
- *Notification* (logisch model bovenop meerdere DB-tabellen)
|
||||
- Velden: id, user-id, type (like, comment, friend-request, ...), payload, status (gelezen/ongelezen).
|
||||
- Verantwoordelijkheid: representeert een gebeurtenis die aan de gebruiker wordt gecommuniceerd; gebruikt samen met subscription- en preference-modellen voor Web Push.
|
||||
|
||||
== Relatie met frontend en stores
|
||||
|
||||
In de frontend worden deze modellen gebruikt in Svelte-componenten en Svelte stores:
|
||||
|
||||
- In `src/lib/stores/api-sync.ts` wordt een typesafe representatie van finds, comments, likes en ratings bijgehouden.
|
||||
- Components in `src/lib/components/finds/` en `src/lib/components/map/` ontvangen deze modellen via props en renderen ze in de UI.
|
||||
- Door overal TypeScript-typen te gebruiken, blijven de klassediagram-concepten consistent tussen database, serverlogica en frontend.
|
||||
|
||||
Het klassediagram helpt zo om de logische structuur van de applicatie in één oogopslag te begrijpen en vormt een brug tussen het relationele ERD en de concrete implementatie in TypeScript en Svelte.
|
||||
78
docs/sections/optimalisaties.typ
Normal file
78
docs/sections/optimalisaties.typ
Normal file
@@ -0,0 +1,78 @@
|
||||
#heading[Optimalisaties en resultaten]
|
||||
|
||||
Tijdens de ontwikkeling van Serengo zijn meerdere optimalisatiegolven doorgevoerd op het gebied van performance, UX, architectuur en deployment. Dit hoofdstuk vat de belangrijkste stappen en hun impact samen.
|
||||
|
||||
== Performance- en SEO-optimalisaties
|
||||
|
||||
Op 7 oktober is een grote optimalisatieronde uitgevoerd gericht op SEO, PWA en laadtijden:
|
||||
|
||||
- *SEO-verbeteringen*
|
||||
- Toevoegen en bijwerken van meta-tags en Open Graph-data.
|
||||
- Automatische generatie van `sitemap.xml` voor betere indexeerbaarheid.
|
||||
- *PWA-verbeteringen*
|
||||
- Uitbreiding van de service worker voor caching van statische assets en kernroutes.
|
||||
- Optimalisatie van `manifest.json` (iconen, naamgeving, start-URL).
|
||||
- *Performance*
|
||||
- Compressie van de achtergrondafbeelding (± 50% kleiner; van ~4.2MB naar ~2.1MB).
|
||||
- Vite-configoptimalisaties en fixen van build-issues.
|
||||
|
||||
Gemeten resultaten (op basis van Lighthouse-logs):
|
||||
|
||||
- Homepageload verbeterd van ongeveer 2.5s naar 1.2s.
|
||||
- Largest Contentful Paint gedaald van ±1.8s naar ±0.9s.
|
||||
- Betere stabiliteit door caching en service worker-ondersteuning.
|
||||
|
||||
== Architecturale verbeteringen
|
||||
|
||||
In Phase 6 en 7 is de interne architectuur grondig herzien:
|
||||
|
||||
- *Overgang naar location-gecentreerd datamodel*
|
||||
- Scheiding tussen `locations` en `finds`, met meerdere finds per locatie.
|
||||
- Normalisatie van locatiedata (minder duplicatie, betere querymogelijkheden).
|
||||
- Transactieve migraties en data-integriteitscontroles tijdens de overgang.
|
||||
|
||||
- *Sync-service en api-sync-laag*
|
||||
- Implementatie van een centrale sync-service (`api-sync.ts`) voor optimistic updates.
|
||||
- Automatische rollback bij falende API-calls, waardoor inconsistenties worden voorkomen.
|
||||
- Vermindering van dubbele logica in componenten en eenduidige bron van waarheid voor find-, comment-, like- en ratingdata.
|
||||
|
||||
Deze ingrepen verhogen zowel de schaalbaarheid (efficiëntere queries, minder redundantie) als de gebruikerservaring (snellere, soepelere UI).
|
||||
|
||||
== UX- en mapoptimalisaties
|
||||
|
||||
Een belangrijke focus lag op de kaart- en navigatie-ervaring:
|
||||
|
||||
- *Fullscreen map + sidebar*
|
||||
- Introductie van een fullscreen kaart met een uitschuifbare zijbalk voor finds.
|
||||
- Oplossing van overscroll- en overflowproblemen in lijsten.
|
||||
|
||||
- *Dynamische mapcentrering*
|
||||
- Intelligente centrering van de kaart afhankelijk van sidebar-positie (desktop vs. mobiel).
|
||||
- Voorkomen van storende autozoom tijdens het volgen van locaties.
|
||||
|
||||
- *Marker- en layoutverbeteringen*
|
||||
- Toevoegen van location markers, clustering en betere positionering.
|
||||
- UI-finetuning voor FindPreview, CommentsList en andere componenten.
|
||||
|
||||
Resultaat: gebruikers zien hun find altijd in het zichtbare deel van de kaart, en navigeren vloeiend tussen locaties en finds.
|
||||
|
||||
== Mediaperformance en veiligheid
|
||||
|
||||
Om zowel performance als security te verbeteren, zijn verschillende stappen gezet rond media:
|
||||
|
||||
- Invoering van een lokale mediaproxy (`/api/media/[...path]`) in plaats van directe Cloudflare R2-URL's.
|
||||
- CSP-fixes om externe resources gecontroleerd toe te laten.
|
||||
- WebP/JPEG-pipeline voor efficiëntere afbeeldingen met fallback-ondersteuning.
|
||||
|
||||
Dit zorgt voor snellere laadtijden, minder kans op CSP-gerelateerde fouten en betere controle over de media-aflevering.
|
||||
|
||||
== Deployment- en operationele optimalisaties
|
||||
|
||||
Om deployments robuust en reproduceerbaar te maken zijn onder meer de volgende verbeteringen geïntroduceerd:
|
||||
|
||||
- Multi-stage Docker build voor kleinere, efficiëntere images.
|
||||
- Verplaatsing van Drizzle naar production dependencies zodat migraties binnen de container kunnen draaien.
|
||||
- Een entrypoint-script dat bij het starten van de container automatisch database-migraties uitvoert.
|
||||
- Health checks en verbeterde logging voor snellere foutdetectie.
|
||||
|
||||
Samen maken deze optimalisaties Serengo geschikt voor langdurige, stabiele hosting met goede gebruikerservaring en onderhoudbaarheid.
|
||||
31
docs/sections/screenshots.typ
Normal file
31
docs/sections/screenshots.typ
Normal file
@@ -0,0 +1,31 @@
|
||||
#heading[Screenshots en gebruiksscenario's]
|
||||
|
||||
In dit hoofdstuk worden enkele representatieve screenshots van de applicatie opgenomen. Om het
|
||||
Typst-document compileerbaar te houden, zijn er placeholder-afbeeldingen voorzien in
|
||||
`docs/screenshots/`. Vervang deze placeholders later door echte screenshots (bijvoorbeeld PNG) en
|
||||
pas de bestandsnamen/paden hieronder aan.
|
||||
|
||||
#figure(
|
||||
image("../screenshots/home.svg"),
|
||||
caption: [Startscherm met fullscreen kaart en zijbalk met finds]
|
||||
)
|
||||
|
||||
#figure(
|
||||
image("../screenshots/find-detail.svg"),
|
||||
caption: [Detailpagina van een find met media, likes, comments en rating]
|
||||
)
|
||||
|
||||
#figure(
|
||||
image("../screenshots/friends.svg"),
|
||||
caption: [Vriendenoverzicht en privacy-bewuste filtering van finds]
|
||||
)
|
||||
|
||||
#figure(
|
||||
image("../screenshots/notifications.svg"),
|
||||
caption: [In-app notificaties en Web Push-permissies]
|
||||
)
|
||||
|
||||
#figure(
|
||||
image("../screenshots/mobile.svg"),
|
||||
caption: [Mobiele weergave met zijbalk en dynamische mapcentrering]
|
||||
)
|
||||
31
docs/sections/voor-wie-is-serengo.typ
Normal file
31
docs/sections/voor-wie-is-serengo.typ
Normal file
@@ -0,0 +1,31 @@
|
||||
#heading[Voor wie is Serengo?]
|
||||
|
||||
Serengo is ontworpen voor kleine tot middelgrote groepen gebruikers die waarde hechten aan het gezamenlijk ontdekken, bewaren en herbeleven van interessante plaatsen. In plaats van een volledig open, anoniem social media-platform, richt Serengo zich op contexten waar onderling vertrouwen en controle over zichtbaarheid belangrijk zijn.
|
||||
|
||||
== Primaire doelgroep
|
||||
|
||||
- *Vriendengroepen en kennissenkringen* die samen een kaart willen opbouwen van favoriete cafés, restaurants, uitzichtpunten, wandelroutes of andere "hidden gems".
|
||||
- *Lokale communities* (bijvoorbeeld studentenverenigingen, hobbygroepen of buurtinitiatieven) die interessante locaties in hun omgeving willen cureren en onderling delen.
|
||||
- *Reizigers en explorers* die hun mooiste ontdekkingen op reis willen vastleggen, documenteren met media en nadien eenvoudig terugvinden op een kaart.
|
||||
|
||||
== Secundaire doelgroep
|
||||
|
||||
- *Individuele gebruikers* die een persoonlijke kaart van favoriete plaatsen willen beheren zonder dit publiek op een grote social media-site te delen.
|
||||
- *Early adopters en ontwikkelaars* die geïnteresseerd zijn in moderne webtechnologie (SvelteKit, Drizzle ORM, Web Push, MapLibre) en een concreet voorbeeldproject zoeken.
|
||||
|
||||
== Behoeften en use-cases
|
||||
|
||||
De belangrijkste behoeften die Serengo adresseert zijn:
|
||||
|
||||
- *Gecontroleerde zichtbaarheid* – via het vriendensysteem en privacyfilters (All/Public/Friends/Mine) kan de eigenaar per find bepalen wie wat te zien krijgt.
|
||||
- *Rijke context rond locaties* – naast coördinaten en naam biedt Serengo ruimte voor verhalen, foto's, video's, likes, comments en ratings.
|
||||
- *Gezamenlijk geheugen* – meerdere gebruikers kunnen finds aan dezelfde locatie koppelen zodat er een gedeelde geschiedenis per plaats ontstaat.
|
||||
- *Eenvoudig delen* – via deelbare URL's en de Web Share API kunnen finds snel met anderen worden gedeeld.
|
||||
|
||||
== Link met functionaliteit
|
||||
|
||||
De ontwerpkeuzes in de applicatie sluiten direct aan bij deze doelgroep:
|
||||
|
||||
- Het *vriendensysteem* en de *privacy-bewuste filtering* maken het veilig om persoonlijke plaatsen te delen binnen een beperkte kring.
|
||||
- *Ratings en comments* maken het mogelijk om samen te reflecteren op plaatsen en aanbevelingen te doen.
|
||||
- De *fullscreen kaartinterface* met slimme centrering en clustering ondersteunt het ontdekken van nieuwe locaties op een intuïtieve, visuele manier.
|
||||
16
docs/sections/wat-is-serengo.typ
Normal file
16
docs/sections/wat-is-serengo.typ
Normal file
@@ -0,0 +1,16 @@
|
||||
#heading[Wat is Serengo?]
|
||||
|
||||
Serengo is een locatie-gebaseerde sociale webapplicatie, gebouwd met SvelteKit [@sveltekit-docs],
|
||||
waarin gebruikers zogenaamde 'finds' kunnen vastleggen en delen. Een find is een combinatie van een plaats op de kaart, een kort verhaal en
|
||||
bijhorende media (foto's en video's). Gebruikers kunnen zo hun favoriete plekken documenteren,
|
||||
waarderen en met anderen delen.
|
||||
|
||||
Het project combineert interactieve kaarten, moderne webtechnologie en sociale functionaliteit tot één samenhorende ervaring:
|
||||
|
||||
- *Kaart-centrische interface* – de startpagina toont een fullscreen kaart (MapLibre GL JS [@maplibre-docs]) waarop finds als markers verschijnen. Via een zijbalk kunnen gebruikers finds verkennen, filteren en selecteren.
|
||||
- *Finds met rijke media* – bij elke find horen een titel, beschrijving, locatie en één of meerdere media-items (beelden en video's). Media worden opgeslagen in Cloudflare R2 [@cloudflare-r2-docs] en veilig ontsloten via signed URLs en een lokale mediaproxy.
|
||||
- *Sociale interacties* – gebruikers kunnen finds liken, commenten en beoordelen (ratings). Vriendschapsrelaties bepalen wie welke finds mag zien: publiek, alleen vrienden of enkel de eigenaar.
|
||||
- *Realtime en gebruiksvriendelijke updates* – door een sync-service en een centrale `api-sync` store worden wijzigingen eerst optimistisch in de UI toegepast en daarna met de database gesynchroniseerd. Bij fouten volgt automatisch een rollback.
|
||||
- *Notificaties en PWA* – via een service worker en Web Push [@web-push-spec] worden gebruikers op de hoogte gebracht van gebeurtenissen zoals likes, comments en vriendschapsverzoeken. De applicatie is ingericht als Progressive Web App met caching en offline-ondersteuning voor kernfunctionaliteit.
|
||||
|
||||
In essentie is Serengo een digitale kaart vol persoonlijke verhalen. Het biedt de technische infrastructuur om plaatsen vast te leggen, te verrijken met context en die ervaringen gecontroleerd te (her)delen binnen een sociale omgeving.
|
||||
Reference in New Issue
Block a user